isync-1.4.4/0000755000175000001440000000000014152374120007641 500000000000000isync-1.4.4/configure0000755000175000001440000060516414152373730011512 00000000000000#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.71 for isync 1.4.4. # # # Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation, # Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh as_nop=: if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else $as_nop case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi # Reset variables that may have inherited troublesome values from # the environment. # IFS needs to be set, to space, tab, and newline, in precisely that order. # (If _AS_PATH_WALK were called with IFS unset, it would have the # side effect of setting IFS to empty, thus disabling word splitting.) # Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl IFS=" "" $as_nl" PS1='$ ' PS2='> ' PS4='+ ' # Ensure predictable behavior from utilities with locale-dependent output. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # We cannot yet rely on "unset" to work, but we need these variables # to be unset--not just set to an empty or harmless value--now, to # avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct # also avoids known problems related to "unset" and subshell syntax # in other old shells (e.g. bash 2.01 and pdksh 5.2.14). for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH do eval test \${$as_var+y} \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done # Ensure that fds 0, 1, and 2 are open. if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="as_nop=: if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else \$as_nop case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ) then : else \$as_nop exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 blah=\$(echo \$(echo blah)) test x\"\$blah\" = xblah || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1" if (eval "$as_required") 2>/dev/null then : as_have_required=yes else $as_nop as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null then : else $as_nop as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && as_run=a "$as_shell" -c "$as_bourne_compatible""$as_required" 2>/dev/null then : CONFIG_SHELL=$as_shell as_have_required=yes if as_run=a "$as_shell" -c "$as_bourne_compatible""$as_suggested" 2>/dev/null then : break 2 fi fi done;; esac as_found=false done IFS=$as_save_IFS if $as_found then : else $as_nop if { test -f "$SHELL" || test -f "$SHELL.exe"; } && as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null then : CONFIG_SHELL=$SHELL as_have_required=yes fi fi if test "x$CONFIG_SHELL" != x then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno then : printf "%s\n" "$0: This script requires a shell more modern than all" printf "%s\n" "$0: the shells that I found on your system." if test ${ZSH_VERSION+y} ; then printf "%s\n" "$0: In particular, zsh $ZSH_VERSION has bugs and should" printf "%s\n" "$0: be upgraded to zsh 4.3.4 or later." else printf "%s\n" "$0: Please tell bug-autoconf@gnu.org about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_nop # --------- # Do nothing but, unlike ":", preserve the value of $?. as_fn_nop () { return $? } as_nop=as_fn_nop # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null then : eval 'as_fn_append () { eval $1+=\$2 }' else $as_nop as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null then : eval 'as_fn_arith () { as_val=$(( $* )) }' else $as_nop as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_nop # --------- # Do nothing but, unlike ":", preserve the value of $?. as_fn_nop () { return $? } as_nop=as_fn_nop # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { printf "%s\n" "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } # Determine whether it's possible to make 'echo' print without a newline. # These variables are no longer used directly by Autoconf, but are AC_SUBSTed # for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac # For backward compatibility with old third-party macros, we provide # the shell variables $as_echo and $as_echo_n. New code should use # AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. as_echo='printf %s\n' as_echo_n='printf %s' rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='isync' PACKAGE_TARNAME='isync' PACKAGE_VERSION='1.4.4' PACKAGE_STRING='isync 1.4.4' PACKAGE_BUGREPORT='' PACKAGE_URL='' # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_STDIO_H # include #endif #ifdef HAVE_STDLIB_H # include #endif #ifdef HAVE_STRING_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_header_c_list= ac_subst_vars='am__EXEEXT_FALSE am__EXEEXT_TRUE LTLIBOBJS LIBOBJS KEYCHAIN_LIBS with_mdconvert_FALSE with_mdconvert_TRUE Z_LIBS DB_LIBS SASL_LIBS SSL_LIBS PKG_CONFIG_LIBDIR PKG_CONFIG_PATH PKG_CONFIG SOCK_LIBS PERL am__fastdepCC_FALSE am__fastdepCC_TRUE CCDEPMODE am__nodep AMDEPBACKSLASH AMDEP_FALSE AMDEP_TRUE am__include DEPDIR OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC MAINT MAINTAINER_MODE_FALSE MAINTAINER_MODE_TRUE AM_BACKSLASH AM_DEFAULT_VERBOSITY AM_DEFAULT_V AM_V CSCOPE ETAGS CTAGS am__untar am__tar AMTAR am__leading_dot SET_MAKE AWK mkdir_p MKDIR_P INSTALL_STRIP_PROGRAM STRIP install_sh MAKEINFO AUTOHEADER AUTOMAKE AUTOCONF ACLOCAL VERSION PACKAGE CYGPATH_W am__isrc INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM target_os target_vendor target_cpu target host_os host_vendor host_cpu host build_os build_vendor build_cpu build target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir runstatedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL am__quote' ac_subst_files='' ac_user_opts=' enable_option_checking enable_silent_rules enable_maintainer_mode enable_dependency_tracking with_ssl with_sasl with_zlib with_macos_keychain ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS PKG_CONFIG PKG_CONFIG_PATH PKG_CONFIG_LIBDIR' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -runstatedir | --runstatedir | --runstatedi | --runstated \ | --runstate | --runstat | --runsta | --runst | --runs \ | --run | --ru | --r) ac_prev=runstatedir ;; -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ | --run=* | --ru=* | --r=*) runstatedir=$ac_optarg ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. printf "%s\n" "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && printf "%s\n" "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures isync 1.4.4 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/isync] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF Program names: --program-prefix=PREFIX prepend PREFIX to installed program names --program-suffix=SUFFIX append SUFFIX to installed program names --program-transform-name=PROGRAM run sed PROGRAM on installed program names System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] --target=TARGET configure for building compilers for TARGET [HOST] _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of isync 1.4.4:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-silent-rules less verbose build output (undo: "make V=1") --disable-silent-rules verbose build output (undo: "make V=0") --disable-maintainer-mode disable make rules and dependencies not useful (and sometimes confusing) to the casual installer --enable-dependency-tracking do not reject slow dependency extractors --disable-dependency-tracking speeds up one-time build Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-ssl=PATH where to look for SSL [detect] --with-sasl=PATH where to look for SASL [detect] --with-zlib use zlib [detect] --with-macos-keychain Support macOS keychain Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory PKG_CONFIG path to pkg-config utility PKG_CONFIG_PATH directories to add to pkg-config's search path PKG_CONFIG_LIBDIR path overriding pkg-config's built-in search path Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to the package provider. _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for configure.gnu first; this name is used for a wrapper for # Metaconfig's "Configure" on case-insensitive file systems. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else printf "%s\n" "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF isync configure 1.4.4 generated by GNU Autoconf 2.71 Copyright (C) 2021 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest.beam if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext then : ac_retval=0 else $as_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_run LINENO # ---------------------- # Try to run conftest.$ac_ext, and return whether this succeeded. Assumes that # executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; } then : ac_retval=0 else $as_nop printf "%s\n" "$as_me: program exited with status $ac_status" >&5 printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO" then : eval "$3=yes" else $as_nop eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest.beam conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext } then : ac_retval=0 else $as_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. */ #include #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main (void) { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : eval "$3=yes" else $as_nop eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func ac_configure_args_raw= for ac_arg do case $ac_arg in *\'*) ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append ac_configure_args_raw " '$ac_arg'" done case $ac_configure_args_raw in *$as_nl*) ac_safe_unquote= ;; *) ac_unsafe_z='|&;<>()$`\\"*?[ '' ' # This string ends in space, tab. ac_unsafe_a="$ac_unsafe_z#~" ac_safe_unquote="s/ '\\([^$ac_unsafe_a][^$ac_unsafe_z]*\\)'/ \\1/g" ac_configure_args_raw=` printf "%s\n" "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;; esac cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by isync $as_me 1.4.4, which was generated by GNU Autoconf 2.71. Invocation command line was $ $0$ac_configure_args_raw _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac printf "%s\n" "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Sanitize IFS. IFS=" "" $as_nl" # Save into config.log some information that might help in debugging. { echo printf "%s\n" "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo printf "%s\n" "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then printf "%s\n" "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then printf "%s\n" "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && printf "%s\n" "$as_me: caught signal $ac_signal" printf "%s\n" "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h printf "%s\n" "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. printf "%s\n" "#define PACKAGE_NAME \"$PACKAGE_NAME\"" >>confdefs.h printf "%s\n" "#define PACKAGE_TARNAME \"$PACKAGE_TARNAME\"" >>confdefs.h printf "%s\n" "#define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >>confdefs.h printf "%s\n" "#define PACKAGE_STRING \"$PACKAGE_STRING\"" >>confdefs.h printf "%s\n" "#define PACKAGE_BUGREPORT \"$PACKAGE_BUGREPORT\"" >>confdefs.h printf "%s\n" "#define PACKAGE_URL \"$PACKAGE_URL\"" >>confdefs.h # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. if test -n "$CONFIG_SITE"; then ac_site_files="$CONFIG_SITE" elif test "x$prefix" != xNONE; then ac_site_files="$prefix/share/config.site $prefix/etc/config.site" else ac_site_files="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi for ac_site_file in $ac_site_files do case $ac_site_file in #( */*) : ;; #( *) : ac_site_file=./$ac_site_file ;; esac if test -f "$ac_site_file" && test -r "$ac_site_file"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 printf "%s\n" "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 printf "%s\n" "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Test code for whether the C compiler supports C89 (global declarations) ac_c_conftest_c89_globals=' /* Does the compiler advertise C89 conformance? Do not test the value of __STDC__, because some compilers set it to 0 while being otherwise adequately conformant. */ #if !defined __STDC__ # error "Compiler does not advertise C89 conformance" #endif #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */ struct buf { int x; }; struct buf * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not \xHH hex character constants. These do not provoke an error unfortunately, instead are silently treated as an "x". The following induces an error, until -std is added to get proper ANSI mode. Curiously \x00 != x always comes out true, for an array size at least. It is necessary to write \x00 == 0 to get something that is true only with -std. */ int osf4_cc_array ['\''\x00'\'' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) '\''x'\'' int xlc6_cc_array[FOO(a) == '\''x'\'' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, int *(*)(struct buf *, struct stat *, int), int, int);' # Test code for whether the C compiler supports C89 (body of main). ac_c_conftest_c89_main=' ok |= (argc == 0 || f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]); ' # Test code for whether the C compiler supports C99 (global declarations) ac_c_conftest_c99_globals=' // Does the compiler advertise C99 conformance? #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L # error "Compiler does not advertise C99 conformance" #endif #include extern int puts (const char *); extern int printf (const char *, ...); extern int dprintf (int, const char *, ...); extern void *malloc (size_t); // Check varargs macros. These examples are taken from C99 6.10.3.5. // dprintf is used instead of fprintf to avoid needing to declare // FILE and stderr. #define debug(...) dprintf (2, __VA_ARGS__) #define showlist(...) puts (#__VA_ARGS__) #define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) static void test_varargs_macros (void) { int x = 1234; int y = 5678; debug ("Flag"); debug ("X = %d\n", x); showlist (The first, second, and third items.); report (x>y, "x is %d but y is %d", x, y); } // Check long long types. #define BIG64 18446744073709551615ull #define BIG32 4294967295ul #define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) #if !BIG_OK #error "your preprocessor is broken" #endif #if BIG_OK #else #error "your preprocessor is broken" #endif static long long int bignum = -9223372036854775807LL; static unsigned long long int ubignum = BIG64; struct incomplete_array { int datasize; double data[]; }; struct named_init { int number; const wchar_t *name; double average; }; typedef const char *ccp; static inline int test_restrict (ccp restrict text) { // See if C++-style comments work. // Iterate through items via the restricted pointer. // Also check for declarations in for loops. for (unsigned int i = 0; *(text+i) != '\''\0'\''; ++i) continue; return 0; } // Check varargs and va_copy. static bool test_varargs (const char *format, ...) { va_list args; va_start (args, format); va_list args_copy; va_copy (args_copy, args); const char *str = ""; int number = 0; float fnumber = 0; while (*format) { switch (*format++) { case '\''s'\'': // string str = va_arg (args_copy, const char *); break; case '\''d'\'': // int number = va_arg (args_copy, int); break; case '\''f'\'': // float fnumber = va_arg (args_copy, double); break; default: break; } } va_end (args_copy); va_end (args); return *str && number && fnumber; } ' # Test code for whether the C compiler supports C99 (body of main). ac_c_conftest_c99_main=' // Check bool. _Bool success = false; success |= (argc != 0); // Check restrict. if (test_restrict ("String literal") == 0) success = true; char *restrict newvar = "Another string"; // Check varargs. success &= test_varargs ("s, d'\'' f .", "string", 65, 34.234); test_varargs_macros (); // Check flexible array members. struct incomplete_array *ia = malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10)); ia->datasize = 10; for (int i = 0; i < ia->datasize; ++i) ia->data[i] = i * 1.234; // Check named initializers. struct named_init ni = { .number = 34, .name = L"Test wide string", .average = 543.34343, }; ni.number = 58; int dynamic_array[ni.number]; dynamic_array[0] = argv[0][0]; dynamic_array[ni.number - 1] = 543; // work around unused variable warnings ok |= (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == '\''x'\'' || dynamic_array[ni.number - 1] != 543); ' # Test code for whether the C compiler supports C11 (global declarations) ac_c_conftest_c11_globals=' // Does the compiler advertise C11 conformance? #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L # error "Compiler does not advertise C11 conformance" #endif // Check _Alignas. char _Alignas (double) aligned_as_double; char _Alignas (0) no_special_alignment; extern char aligned_as_int; char _Alignas (0) _Alignas (int) aligned_as_int; // Check _Alignof. enum { int_alignment = _Alignof (int), int_array_alignment = _Alignof (int[100]), char_alignment = _Alignof (char) }; _Static_assert (0 < -_Alignof (int), "_Alignof is signed"); // Check _Noreturn. int _Noreturn does_not_return (void) { for (;;) continue; } // Check _Static_assert. struct test_static_assert { int x; _Static_assert (sizeof (int) <= sizeof (long int), "_Static_assert does not work in struct"); long int y; }; // Check UTF-8 literals. #define u8 syntax error! char const utf8_literal[] = u8"happens to be ASCII" "another string"; // Check duplicate typedefs. typedef long *long_ptr; typedef long int *long_ptr; typedef long_ptr long_ptr; // Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1. struct anonymous { union { struct { int i; int j; }; struct { int k; long int l; } w; }; int m; } v1; ' # Test code for whether the C compiler supports C11 (body of main). ac_c_conftest_c11_main=' _Static_assert ((offsetof (struct anonymous, i) == offsetof (struct anonymous, w.k)), "Anonymous union alignment botch"); v1.i = 2; v1.w.k = 5; ok |= v1.i != 5; ' # Test code for whether the C compiler supports C11 (complete). ac_c_conftest_c11_program="${ac_c_conftest_c89_globals} ${ac_c_conftest_c99_globals} ${ac_c_conftest_c11_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} ${ac_c_conftest_c99_main} ${ac_c_conftest_c11_main} return ok; } " # Test code for whether the C compiler supports C99 (complete). ac_c_conftest_c99_program="${ac_c_conftest_c89_globals} ${ac_c_conftest_c99_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} ${ac_c_conftest_c99_main} return ok; } " # Test code for whether the C compiler supports C89 (complete). ac_c_conftest_c89_program="${ac_c_conftest_c89_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} return ok; } " as_fn_append ac_header_c_list " stdio.h stdio_h HAVE_STDIO_H" as_fn_append ac_header_c_list " stdlib.h stdlib_h HAVE_STDLIB_H" as_fn_append ac_header_c_list " string.h string_h HAVE_STRING_H" as_fn_append ac_header_c_list " inttypes.h inttypes_h HAVE_INTTYPES_H" as_fn_append ac_header_c_list " stdint.h stdint_h HAVE_STDINT_H" as_fn_append ac_header_c_list " strings.h strings_h HAVE_STRINGS_H" as_fn_append ac_header_c_list " sys/stat.h sys_stat_h HAVE_SYS_STAT_H" as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H" as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H" # Auxiliary files required by this configure script. ac_aux_files="compile missing install-sh config.guess config.sub" # Locations in which to look for auxiliary files. ac_aux_dir_candidates="${srcdir}${PATH_SEPARATOR}${srcdir}/..${PATH_SEPARATOR}${srcdir}/../.." # Search for a directory containing all of the required auxiliary files, # $ac_aux_files, from the $PATH-style list $ac_aux_dir_candidates. # If we don't find one directory that contains all the files we need, # we report the set of missing files from the *first* directory in # $ac_aux_dir_candidates and give up. ac_missing_aux_files="" ac_first_candidate=: printf "%s\n" "$as_me:${as_lineno-$LINENO}: looking for aux files: $ac_aux_files" >&5 as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in $ac_aux_dir_candidates do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac as_found=: printf "%s\n" "$as_me:${as_lineno-$LINENO}: trying $as_dir" >&5 ac_aux_dir_found=yes ac_install_sh= for ac_aux in $ac_aux_files do # As a special case, if "install-sh" is required, that requirement # can be satisfied by any of "install-sh", "install.sh", or "shtool", # and $ac_install_sh is set appropriately for whichever one is found. if test x"$ac_aux" = x"install-sh" then if test -f "${as_dir}install-sh"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install-sh found" >&5 ac_install_sh="${as_dir}install-sh -c" elif test -f "${as_dir}install.sh"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install.sh found" >&5 ac_install_sh="${as_dir}install.sh -c" elif test -f "${as_dir}shtool"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}shtool found" >&5 ac_install_sh="${as_dir}shtool install -c" else ac_aux_dir_found=no if $ac_first_candidate; then ac_missing_aux_files="${ac_missing_aux_files} install-sh" else break fi fi else if test -f "${as_dir}${ac_aux}"; then printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}${ac_aux} found" >&5 else ac_aux_dir_found=no if $ac_first_candidate; then ac_missing_aux_files="${ac_missing_aux_files} ${ac_aux}" else break fi fi fi done if test "$ac_aux_dir_found" = yes; then ac_aux_dir="$as_dir" break fi ac_first_candidate=false as_found=false done IFS=$as_save_IFS if $as_found then : else $as_nop as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. if test -f "${ac_aux_dir}config.guess"; then ac_config_guess="$SHELL ${ac_aux_dir}config.guess" fi if test -f "${ac_aux_dir}config.sub"; then ac_config_sub="$SHELL ${ac_aux_dir}config.sub" fi if test -f "$ac_aux_dir/configure"; then ac_configure="$SHELL ${ac_aux_dir}configure" fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 printf "%s\n" "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 printf "%s\n" "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 printf "%s\n" "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 printf "%s\n" "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 printf "%s\n" "$as_me: former value: \`$ac_old_val'" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 printf "%s\n" "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`printf "%s\n" "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 printf "%s\n" "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`${MAKE-make} distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_config_headers="$ac_config_headers autodefs.h" # Make sure we can run config.sub. $SHELL "${ac_aux_dir}config.sub" sun4 >/dev/null 2>&1 || as_fn_error $? "cannot run $SHELL ${ac_aux_dir}config.sub" "$LINENO" 5 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 printf %s "checking build system type... " >&6; } if test ${ac_cv_build+y} then : printf %s "(cached) " >&6 else $as_nop ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "${ac_aux_dir}config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "${ac_aux_dir}config.sub" $ac_build_alias` || as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $ac_build_alias failed" "$LINENO" 5 fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 printf "%s\n" "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' set x $ac_cv_build shift build_cpu=$1 build_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: build_os=$* IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 printf %s "checking host system type... " >&6; } if test ${ac_cv_host+y} then : printf %s "(cached) " >&6 else $as_nop if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "${ac_aux_dir}config.sub" $host_alias` || as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $host_alias failed" "$LINENO" 5 fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 printf "%s\n" "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' set x $ac_cv_host shift host_cpu=$1 host_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: host_os=$* IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking target system type" >&5 printf %s "checking target system type... " >&6; } if test ${ac_cv_target+y} then : printf %s "(cached) " >&6 else $as_nop if test "x$target_alias" = x; then ac_cv_target=$ac_cv_host else ac_cv_target=`$SHELL "${ac_aux_dir}config.sub" $target_alias` || as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $target_alias failed" "$LINENO" 5 fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5 printf "%s\n" "$ac_cv_target" >&6; } case $ac_cv_target in *-*-*) ;; *) as_fn_error $? "invalid value of canonical target" "$LINENO" 5;; esac target=$ac_cv_target ac_save_IFS=$IFS; IFS='-' set x $ac_cv_target shift target_cpu=$1 target_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: target_os=$* IFS=$ac_save_IFS case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac # The aliases save the names the user supplied, while $host etc. # will get canonicalized. test -n "$target_alias" && test "$program_prefix$program_suffix$program_transform_name" = \ NONENONEs,x,x, && program_prefix=${target_alias}- am__api_version='1.16' # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 printf %s "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if test ${ac_cv_path_install+y} then : printf %s "(cached) " >&6 else $as_nop as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac # Account for fact that we put trailing slashes in our PATH walk. case $as_dir in #(( ./ | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir/" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test ${ac_cv_path_install+y}; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 printf "%s\n" "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 printf %s "checking whether build environment is sane... " >&6; } # 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]*) as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; esac case $srcdir in *[\\\"\#\$\&\'\`$am_lf\ \ ]*) as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;; 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 ( am_has_slept=no for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file 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 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". as_fn_error $? "ls -t appears to fail. Make sure there is not a broken alias in your environment" "$LINENO" 5 fi if test "$2" = conftest.file || test $am_try -eq 2; then break fi # Just in case. sleep 1 am_has_slept=yes done test "$2" = conftest.file ) then # Ok. : else as_fn_error $? "newly created file is older than distributed files! Check your system clock" "$LINENO" 5 fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if grep 'slept: no' conftest.file >/dev/null 2>&1; then ( sleep 1 ) & am_sleep_pid=$! fi rm -f conftest.file test "$program_prefix" != NONE && program_transform_name="s&^&$program_prefix&;$program_transform_name" # Use a double $ so make ignores it. test "$program_suffix" != NONE && program_transform_name="s&\$&$program_suffix&;$program_transform_name" # Double any \ or $. # By default was `s,x,x', remove it if useless. ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' program_transform_name=`printf "%s\n" "$program_transform_name" | sed "$ac_script"` # Expand $ac_aux_dir to an absolute path. am_aux_dir=`cd "$ac_aux_dir" && pwd` if test x"${MISSING+set}" != xset; then MISSING="\${SHELL} '$am_aux_dir/missing'" fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 printf "%s\n" "$as_me: WARNING: 'missing' script is too old or missing" >&2;} fi if test x"${install_sh+set}" != 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 # 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. if test "$cross_compiling" != no; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_STRIP+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 printf "%s\n" "$STRIP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_STRIP+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 printf "%s\n" "$ac_ct_STRIP" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a race-free mkdir -p" >&5 printf %s "checking for a race-free mkdir -p... " >&6; } if test -z "$MKDIR_P"; then if test ${ac_cv_path_mkdir+y} then : printf %s "(cached) " >&6 else $as_nop as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_prog in mkdir gmkdir; do for ac_exec_ext in '' $ac_executable_extensions; do as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext" || continue case `"$as_dir$ac_prog$ac_exec_ext" --version 2>&1` in #( 'mkdir ('*'coreutils) '* | \ 'BusyBox '* | \ 'mkdir (fileutils) '4.1*) ac_cv_path_mkdir=$as_dir$ac_prog$ac_exec_ext break 3;; esac done done done IFS=$as_save_IFS fi test -d ./--version && rmdir ./--version if test ${ac_cv_path_mkdir+y}; then MKDIR_P="$ac_cv_path_mkdir -p" else # As a last resort, use the slow shell script. Don't cache a # value for MKDIR_P within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. MKDIR_P="$ac_install_sh -d" fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 printf "%s\n" "$MKDIR_P" >&6; } for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_AWK+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_AWK="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 printf "%s\n" "$AWK" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$AWK" && break done { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 printf %s "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`printf "%s\n" "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval test \${ac_cv_prog_make_${ac_make}_set+y} then : printf %s "(cached) " >&6 else $as_nop cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } SET_MAKE= else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi 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 # Check whether --enable-silent-rules was given. if test ${enable_silent_rules+y} then : enableval=$enable_silent_rules; fi case $enable_silent_rules in # ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=1;; esac am_make=${MAKE-make} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 printf %s "checking whether $am_make supports nested variables... " >&6; } if test ${am_cv_make_support_nested_variables+y} then : printf %s "(cached) " >&6 else $as_nop if printf "%s\n" 'TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 printf "%s\n" "$am_cv_make_support_nested_variables" >&6; } if test $am_cv_make_support_nested_variables = yes; then AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AM_BACKSLASH='\' if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." am__isrc=' -I$(srcdir)' # test to see if srcdir already configured if test -f $srcdir/config.status; then as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 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 # Define the identity of the package. PACKAGE='isync' VERSION='1.4.4' printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h printf "%s\n" "#define VERSION \"$VERSION\"" >>confdefs.h # Some tools Automake needs. ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # mkdir_p='$(MKDIR_P)' # We need awk for the "check" target (and possibly the TAP driver). The # system "awk" is bad on some platforms. # Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AMTAR='$${TAR-tar}' # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar pax cpio none' am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -' # Variables for tags utilities; see am/tags.am if test -z "$CTAGS"; then CTAGS=ctags fi if test -z "$ETAGS"; then ETAGS=etags fi if test -z "$CSCOPE"; then CSCOPE=cscope fi # POSIX will say in a future version that running "rm -f" with no argument # is OK; and we want to be able to make that assumption in our Makefile # recipes. So use an aggressive probe to check that the usage we want is # actually supported "in the wild" to an acceptable degree. # See automake bug#10828. # To make any issue more visible, cause the running configure to be aborted # by default if the 'rm' program in use doesn't match our expectations; the # user can still override this though. if rm -f && rm -fr && rm -rf; then : OK; else cat >&2 <<'END' Oops! Your 'rm' program seems unable to run without file operands specified on the command line, even when the '-f' option is present. This is contrary to the behaviour of most rm programs out there, and not conforming with the upcoming POSIX standard: Please tell bug-automake@gnu.org about your system, including the value of your $PATH and any error possibly output before this message. This can help us improve future automake versions. END if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then echo 'Configuration will proceed anyway, since you have set the' >&2 echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 echo >&2 else cat >&2 <<'END' Aborting the configuration process, to ensure you take notice of the issue. You can download and install GNU coreutils to get an 'rm' implementation that behaves properly: . If you want to complete the configuration process using your problematic 'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM to "yes", and re-run configure. END as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5 fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable maintainer-specific portions of Makefiles" >&5 printf %s "checking whether to enable maintainer-specific portions of Makefiles... " >&6; } # Check whether --enable-maintainer-mode was given. if test ${enable_maintainer_mode+y} then : enableval=$enable_maintainer_mode; USE_MAINTAINER_MODE=$enableval else $as_nop USE_MAINTAINER_MODE=yes fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $USE_MAINTAINER_MODE" >&5 printf "%s\n" "$USE_MAINTAINER_MODE" >&6; } if test $USE_MAINTAINER_MODE = yes; then MAINTAINER_MODE_TRUE= MAINTAINER_MODE_FALSE='#' else MAINTAINER_MODE_TRUE='#' MAINTAINER_MODE_FALSE= fi MAINT=$MAINTAINER_MODE_TRUE ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then if test "$as_dir$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. set dummy ${ac_tool_prefix}clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}clang" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "clang", so it can be a program name with args. set dummy clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="clang" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi fi test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion -version; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 printf %s "checking whether the C compiler works... " >&6; } ac_link_default=`printf "%s\n" "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test ${ac_cv_exeext+y} && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else $as_nop ac_file='' fi if test -z "$ac_file" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 printf %s "checking for C compiler default output file name... " >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 printf "%s\n" "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 printf %s "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else $as_nop { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 printf "%s\n" "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 printf %s "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 printf "%s\n" "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 printf %s "checking for suffix of object files... " >&6; } if test ${ac_cv_objext+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 printf "%s\n" "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 printf %s "checking whether the compiler supports GNU C... " >&6; } if test ${ac_cv_c_compiler_gnu+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_compiler_gnu=yes else $as_nop ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } ac_compiler_gnu=$ac_cv_c_compiler_gnu if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+y} ac_save_CFLAGS=$CFLAGS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 printf %s "checking whether $CC accepts -g... " >&6; } if test ${ac_cv_prog_cc_g+y} then : printf %s "(cached) " >&6 else $as_nop ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes else $as_nop CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else $as_nop ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 printf "%s\n" "$ac_cv_prog_cc_g" >&6; } if test $ac_test_CFLAGS; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi ac_prog_cc_stdc=no if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 printf %s "checking for $CC option to enable C11 features... " >&6; } if test ${ac_cv_prog_cc_c11+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c11=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c11_program _ACEOF for ac_arg in '' -std=gnu11 do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c11=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c11" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c11" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c11" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } CC="$CC $ac_cv_prog_cc_c11" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 ac_prog_cc_stdc=c11 fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 printf %s "checking for $CC option to enable C99 features... " >&6; } if test ${ac_cv_prog_cc_c99+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c99=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c99_program _ACEOF for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c99=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c99" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c99" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c99" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } CC="$CC $ac_cv_prog_cc_c99" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 ac_prog_cc_stdc=c99 fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 printf %s "checking for $CC option to enable C89 features... " >&6; } if test ${ac_cv_prog_cc_c89+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c89_program _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c89" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c89" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } CC="$CC $ac_cv_prog_cc_c89" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 ac_prog_cc_stdc=c89 fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 printf %s "checking whether $CC understands -c and -o together... " >&6; } if test ${am_cv_prog_cc_c_o+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF # Make sure it works both with $CC and with simple cc. # Following AC_PROG_CC_C_O, we do the test twice because some # compilers refuse to overwrite an existing .o file with -o, # though they will create one. am_cv_prog_cc_c_o=yes for am_i in 1 2; do if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5 ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } \ && test -f conftest2.$ac_objext; then : OK else am_cv_prog_cc_c_o=no break fi done rm -f core conftest* unset am_i fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 printf "%s\n" "$am_cv_prog_cc_c_o" >&6; } if test "$am_cv_prog_cc_c_o" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu DEPDIR="${am__leading_dot}deps" ac_config_commands="$ac_config_commands depfiles" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} supports the include directive" >&5 printf %s "checking whether ${MAKE-make} supports the include directive... " >&6; } cat > confinc.mk << 'END' am__doit: @echo this is the am__doit target >confinc.out .PHONY: am__doit END am__include="#" am__quote= # BSD make does it like this. echo '.include "confinc.mk" # ignored' > confmf.BSD # Other make implementations (GNU, Solaris 10, AIX) do it like this. echo 'include confinc.mk # ignored' > confmf.GNU _am_result=no for s in GNU BSD; do { echo "$as_me:$LINENO: ${MAKE-make} -f confmf.$s && cat confinc.out" >&5 (${MAKE-make} -f confmf.$s && cat confinc.out) >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } case $?:`cat confinc.out 2>/dev/null` in #( '0:this is the am__doit target') : case $s in #( BSD) : am__include='.include' am__quote='"' ;; #( *) : am__include='include' am__quote='' ;; esac ;; #( *) : ;; esac if test "$am__include" != "#"; then _am_result="yes ($s style)" break fi done rm -f confinc.* confmf.* { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${_am_result}" >&5 printf "%s\n" "${_am_result}" >&6; } # Check whether --enable-dependency-tracking was given. if test ${enable_dependency_tracking+y} then : enableval=$enable_dependency_tracking; fi if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi if test "x$enable_dependency_tracking" != xno; then AMDEP_TRUE= AMDEP_FALSE='#' else AMDEP_TRUE='#' AMDEP_FALSE= fi depcc="$CC" am_compiler_list= { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 printf %s "checking dependency style of $depcc... " >&6; } if test ${am_cv_CC_dependencies_compiler_type+y} then : printf %s "(cached) " >&6 else $as_nop 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". rm -rf conftest.dir 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_CC_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 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 10 /bin/sh. echo '/* dummy */' > 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 ;; msvc7 | msvc7msys | 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_CC_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CC_dependencies_compiler_type=none fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 printf "%s\n" "$am_cv_CC_dependencies_compiler_type" >&6; } CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then am__fastdepCC_TRUE= am__fastdepCC_FALSE='#' else am__fastdepCC_TRUE='#' am__fastdepCC_FALSE= fi if test "$GCC" = yes; then warnings=" -Wall -Wextra -Wshadow -Wcast-qual -Wformat=2 -Wformat-signedness -Wformat-nonliteral -Wstrict-prototypes -Wno-overlength-strings " CFLAGS="$CFLAGS -pipe -std=c11 -pedantic $(echo $warnings)" fi cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ void fkt(void) { int a = 42; // c99 comment for (int i = 0; i < a; i++) {} // declaration inside for() int b; // declaration after code } // c11 anonymous structs/unions struct base { int a; }; union deriv { struct base gen; struct { int a; int b; }; }; _ACEOF if ac_fn_c_try_compile "$LINENO" then : else $as_nop as_fn_error $? "compiler does not support required C11 features" "$LINENO" 5 fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE" # Extract the first word of "perl", so it can be a program name with args. set dummy perl; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_PERL+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$PERL"; then ac_cv_prog_PERL="$PERL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_PERL="perl" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi PERL=$ac_cv_prog_PERL if test -n "$PERL"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PERL" >&5 printf "%s\n" "$PERL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$PERL" = "x"; then as_fn_error $? "perl not found" "$LINENO" 5 fi need_perl=5.14 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether perl is recent enough" >&5 printf %s "checking whether perl is recent enough... " >&6; } if test ${ob_cv_perl_ver+y} then : printf %s "(cached) " >&6 else $as_nop if $PERL -e "use v$need_perl;" 2> /dev/null; then ob_cv_perl_ver=yes else ob_cv_perl_ver=no fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ob_cv_perl_ver" >&5 printf "%s\n" "$ob_cv_perl_ver" >&6; } if test "x$ob_cv_perl_ver" = "xno"; then as_fn_error $? "perl is too old, need v$need_perl" "$LINENO" 5 fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether strftime supports %z" >&5 printf %s "checking whether strftime supports %z... " >&6; } if test ${ob_cv_strftime_z+y} then : printf %s "(cached) " >&6 else $as_nop if test "$cross_compiling" = yes then : ob_cv_strftime_z="yes (assumed)" else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main(void) { time_t t = 0; char buf[32]; strftime(buf, sizeof(buf), "%z", localtime(&t)); return !(buf[0] == '+' || buf[0] == '-'); } _ACEOF if ac_fn_c_try_run "$LINENO" then : ob_cv_strftime_z=yes else $as_nop ob_cv_strftime_z=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ob_cv_strftime_z" >&5 printf "%s\n" "$ob_cv_strftime_z" >&6; } if test "x$ob_cv_strftime_z" = x"no"; then as_fn_error $? "libc lacks necessary feature" "$LINENO" 5 fi ac_header= ac_cache= for ac_item in $ac_header_c_list do if test $ac_cache; then ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default" if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then printf "%s\n" "#define $ac_item 1" >> confdefs.h fi ac_header= ac_cache= elif test $ac_header; then ac_cache=$ac_item else ac_header=$ac_item fi done if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes then : printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "poll.h" "ac_cv_header_poll_h" "$ac_includes_default" if test "x$ac_cv_header_poll_h" = xyes then : printf "%s\n" "#define HAVE_POLL_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/select.h" "ac_cv_header_sys_select_h" "$ac_includes_default" if test "x$ac_cv_header_sys_select_h" = xyes then : printf "%s\n" "#define HAVE_SYS_SELECT_H 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "vasprintf" "ac_cv_func_vasprintf" if test "x$ac_cv_func_vasprintf" = xyes then : printf "%s\n" "#define HAVE_VASPRINTF 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "strnlen" "ac_cv_func_strnlen" if test "x$ac_cv_func_strnlen" = xyes then : printf "%s\n" "#define HAVE_STRNLEN 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "memrchr" "ac_cv_func_memrchr" if test "x$ac_cv_func_memrchr" = xyes then : printf "%s\n" "#define HAVE_MEMRCHR 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "timegm" "ac_cv_func_timegm" if test "x$ac_cv_func_timegm" = xyes then : printf "%s\n" "#define HAVE_TIMEGM 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for socket in -lsocket" >&5 printf %s "checking for socket in -lsocket... " >&6; } if test ${ac_cv_lib_socket_socket+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lsocket $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char socket (); int main (void) { return socket (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_socket_socket=yes else $as_nop ac_cv_lib_socket_socket=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_socket" >&5 printf "%s\n" "$ac_cv_lib_socket_socket" >&6; } if test "x$ac_cv_lib_socket_socket" = xyes then : SOCK_LIBS="-lsocket" fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for inet_ntoa in -lnsl" >&5 printf %s "checking for inet_ntoa in -lnsl... " >&6; } if test ${ac_cv_lib_nsl_inet_ntoa+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lnsl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char inet_ntoa (); int main (void) { return inet_ntoa (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_nsl_inet_ntoa=yes else $as_nop ac_cv_lib_nsl_inet_ntoa=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_inet_ntoa" >&5 printf "%s\n" "$ac_cv_lib_nsl_inet_ntoa" >&6; } if test "x$ac_cv_lib_nsl_inet_ntoa" = xyes then : SOCK_LIBS="$SOCK_LIBS -lnsl" fi have_ipv6=true sav_LIBS=$LIBS LIBS="$LIBS $SOCK_LIBS" for ac_func in getaddrinfo inet_ntop do : as_ac_var=`printf "%s\n" "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes" then : cat >>confdefs.h <<_ACEOF #define `printf "%s\n" "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF else $as_nop have_ipv6=false fi done LIBS=$sav_LIBS if $have_ipv6; then printf "%s\n" "#define HAVE_IPV6 1" >>confdefs.h fi have_ssl_paths= # Check whether --with-ssl was given. if test ${with_ssl+y} then : withval=$with_ssl; ob_cv_with_ssl=$withval fi if test "x$ob_cv_with_ssl" != xno; then case $ob_cv_with_ssl in ""|yes) if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_PKG_CONFIG+y} then : printf %s "(cached) " >&6 else $as_nop case $PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_path_PKG_CONFIG="$as_dir$ac_word$ac_exec_ext" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi PKG_CONFIG=$ac_cv_path_PKG_CONFIG if test -n "$PKG_CONFIG"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 printf "%s\n" "$PKG_CONFIG" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_path_PKG_CONFIG"; then ac_pt_PKG_CONFIG=$PKG_CONFIG # Extract the first word of "pkg-config", so it can be a program name with args. set dummy pkg-config; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_ac_pt_PKG_CONFIG+y} then : printf %s "(cached) " >&6 else $as_nop case $ac_pt_PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_path_ac_pt_PKG_CONFIG="$as_dir$ac_word$ac_exec_ext" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG if test -n "$ac_pt_PKG_CONFIG"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5 printf "%s\n" "$ac_pt_PKG_CONFIG" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_pt_PKG_CONFIG" = x; then PKG_CONFIG="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac PKG_CONFIG=$ac_pt_PKG_CONFIG fi else PKG_CONFIG="$ac_cv_path_PKG_CONFIG" fi fi if test -n "$PKG_CONFIG"; then _pkg_min_version=0.9.0 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5 printf %s "checking pkg-config is at least version $_pkg_min_version... " >&6; } if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } PKG_CONFIG="" fi fi if test "x$PKG_CONFIG" != "x" ; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking OpenSSL presence with pkg-config" >&5 printf %s "checking OpenSSL presence with pkg-config... " >&6; } if $PKG_CONFIG --exists openssl; then SSL_LIBS=`$PKG_CONFIG --libs-only-l openssl` SSL_LDFLAGS=`$PKG_CONFIG --libs-only-L openssl` SSL_CPPFLAGS=`$PKG_CONFIG --cflags-only-I openssl` have_ssl_paths=yes { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found" >&5 printf "%s\n" "found" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: not found" >&5 printf "%s\n" "not found" >&6; } fi fi ;; *) SSL_LDFLAGS=-L$ob_cv_with_ssl/lib$libsuff SSL_CPPFLAGS=-I$ob_cv_with_ssl/include ;; esac if test -z "$have_ssl_paths"; then sav_LDFLAGS=$LDFLAGS LDFLAGS="$LDFLAGS $SSL_LDFLAGS" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 printf %s "checking for dlopen in -ldl... " >&6; } if test ${ac_cv_lib_dl_dlopen+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char dlopen (); int main (void) { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_dl_dlopen=yes else $as_nop ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 printf "%s\n" "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes then : LIBDL=-ldl fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for X509_cmp in -lcrypto" >&5 printf %s "checking for X509_cmp in -lcrypto... " >&6; } if test ${ac_cv_lib_crypto_X509_cmp+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lcrypto $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char X509_cmp (); int main (void) { return X509_cmp (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_crypto_X509_cmp=yes else $as_nop ac_cv_lib_crypto_X509_cmp=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_crypto_X509_cmp" >&5 printf "%s\n" "$ac_cv_lib_crypto_X509_cmp" >&6; } if test "x$ac_cv_lib_crypto_X509_cmp" = xyes then : LIBCRYPTO=-lcrypto fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for SSL_connect in -lssl" >&5 printf %s "checking for SSL_connect in -lssl... " >&6; } if test ${ac_cv_lib_ssl_SSL_connect+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lssl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char SSL_connect (); int main (void) { return SSL_connect (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_ssl_SSL_connect=yes else $as_nop ac_cv_lib_ssl_SSL_connect=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ssl_SSL_connect" >&5 printf "%s\n" "$ac_cv_lib_ssl_SSL_connect" >&6; } if test "x$ac_cv_lib_ssl_SSL_connect" = xyes then : SSL_LIBS="-lssl $LIBCRYPTO $LIBDL" have_ssl_paths=yes fi LDFLAGS=$sav_LDFLAGS fi sav_CPPFLAGS=$CPPFLAGS CPPFLAGS="$CPPFLAGS $SSL_CPPFLAGS" ac_fn_c_check_header_compile "$LINENO" "openssl/ssl.h" "ac_cv_header_openssl_ssl_h" "$ac_includes_default" if test "x$ac_cv_header_openssl_ssl_h" = xyes then : else $as_nop have_ssl_paths= fi CPPFLAGS=$sav_CPPFLAGS if test -z "$have_ssl_paths"; then if test -n "$ob_cv_with_ssl"; then as_fn_error $? "OpenSSL libs and/or includes were not found where specified" "$LINENO" 5 fi else printf "%s\n" "#define HAVE_LIBSSL 1" >>confdefs.h CPPFLAGS="$CPPFLAGS $SSL_CPPFLAGS" LDFLAGS="$LDFLAGS $SSL_LDFLAGS" fi fi have_sasl_paths= # Check whether --with-sasl was given. if test ${with_sasl+y} then : withval=$with_sasl; ob_cv_with_sasl=$withval fi if test "x$ob_cv_with_sasl" != xno; then case $ob_cv_with_sasl in ""|yes) ;; *) SASL_LDFLAGS=-L$ob_cv_with_sasl/lib$libsuff SASL_CPPFLAGS=-I$ob_cv_with_sasl/include ;; esac if test -z "$have_sasl_paths"; then sav_LDFLAGS=$LDFLAGS LDFLAGS="$LDFLAGS $SASL_LDFLAGS" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sasl_client_init in -lsasl2" >&5 printf %s "checking for sasl_client_init in -lsasl2... " >&6; } if test ${ac_cv_lib_sasl2_sasl_client_init+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lsasl2 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char sasl_client_init (); int main (void) { return sasl_client_init (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_sasl2_sasl_client_init=yes else $as_nop ac_cv_lib_sasl2_sasl_client_init=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sasl2_sasl_client_init" >&5 printf "%s\n" "$ac_cv_lib_sasl2_sasl_client_init" >&6; } if test "x$ac_cv_lib_sasl2_sasl_client_init" = xyes then : SASL_LIBS="-lsasl2" have_sasl_paths=yes fi LDFLAGS=$sav_LDFLAGS fi sav_CPPFLAGS=$CPPFLAGS CPPFLAGS="$CPPFLAGS $SASL_CPPFLAGS" ac_fn_c_check_header_compile "$LINENO" "sasl/sasl.h" "ac_cv_header_sasl_sasl_h" "$ac_includes_default" if test "x$ac_cv_header_sasl_sasl_h" = xyes then : else $as_nop have_sasl_paths= fi CPPFLAGS=$sav_CPPFLAGS if test -z "$have_sasl_paths"; then if test -n "$ob_cv_with_sasl"; then as_fn_error $? "SASL libs and/or includes were not found where specified" "$LINENO" 5 fi else printf "%s\n" "#define HAVE_LIBSASL 1" >>confdefs.h CPPFLAGS="$CPPFLAGS $SASL_CPPFLAGS" LDFLAGS="$LDFLAGS $SASL_LDFLAGS" fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for Berkeley DB >= 4.1" >&5 printf %s "checking for Berkeley DB >= 4.1... " >&6; } if test ${ac_cv_berkdb4+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_berkdb4=no sav_LIBS=$LIBS LIBS="$LIBS -ldb" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { DB *db; db_create(&db, 0, 0); db->truncate(db, 0, 0, 0); db->open(db, 0, "foo", "foo", DB_HASH, DB_CREATE, 0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_berkdb4=yes fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$sav_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_berkdb4" >&5 printf "%s\n" "$ac_cv_berkdb4" >&6; } if test "x$ac_cv_berkdb4" = xyes; then DB_LIBS="-ldb" printf "%s\n" "#define USE_DB 1" >>confdefs.h fi have_zlib= # Check whether --with-zlib was given. if test ${with_zlib+y} then : withval=$with_zlib; ob_cv_with_zlib=$withval fi if test "x$ob_cv_with_zlib" != xno; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for deflate in -lz" >&5 printf %s "checking for deflate in -lz... " >&6; } if test ${ac_cv_lib_z_deflate+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lz $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char deflate (); int main (void) { return deflate (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_z_deflate=yes else $as_nop ac_cv_lib_z_deflate=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_deflate" >&5 printf "%s\n" "$ac_cv_lib_z_deflate" >&6; } if test "x$ac_cv_lib_z_deflate" = xyes then : ac_fn_c_check_header_compile "$LINENO" "zlib.h" "ac_cv_header_zlib_h" "$ac_includes_default" if test "x$ac_cv_header_zlib_h" = xyes then : have_zlib=1 Z_LIBS="-lz" printf "%s\n" "#define HAVE_LIBZ 1" >>confdefs.h fi fi fi if test "x$ac_cv_berkdb4" = xyes; then with_mdconvert_TRUE= with_mdconvert_FALSE='#' else with_mdconvert_TRUE='#' with_mdconvert_FALSE= fi case $target_os in darwin*) darwin=yes ;; *) darwin=no ;; esac # Check whether --with-macos-keychain was given. if test ${with_macos_keychain+y} then : withval=$with_macos_keychain; have_macos_keychain=$withval else $as_nop have_macos_keychain=$darwin fi if test "x$have_macos_keychain" != xno; then if test $darwin = no; then as_fn_error $? "Cannot use macOS Keychain outside macOS." "$LINENO" 5 fi have_macos_keychain=yes printf "%s\n" "#define HAVE_MACOS_KEYCHAIN 1" >>confdefs.h KEYCHAIN_LIBS="-Wl,-framework,Security,-framework,CoreFoundation" fi ac_config_files="$ac_config_files Makefile src/Makefile isync.spec" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test ${\1+y} || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 printf "%s\n" "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 printf "%s\n" "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`printf "%s\n" "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 printf %s "checking that generated files are newer than configure... " >&6; } if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: done" >&5 printf "%s\n" "done" >&6; } if test -n "$EXEEXT"; then am__EXEEXT_TRUE= am__EXEEXT_FALSE='#' else am__EXEEXT_TRUE='#' am__EXEEXT_FALSE= fi if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then as_fn_error $? "conditional \"MAINTAINER_MODE\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then as_fn_error $? "conditional \"AMDEP\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${with_mdconvert_TRUE}" && test -z "${with_mdconvert_FALSE}"; then as_fn_error $? "conditional \"with_mdconvert\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 printf "%s\n" "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh as_nop=: if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else $as_nop case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi # Reset variables that may have inherited troublesome values from # the environment. # IFS needs to be set, to space, tab, and newline, in precisely that order. # (If _AS_PATH_WALK were called with IFS unset, it would have the # side effect of setting IFS to empty, thus disabling word splitting.) # Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl IFS=" "" $as_nl" PS1='$ ' PS2='> ' PS4='+ ' # Ensure predictable behavior from utilities with locale-dependent output. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # We cannot yet rely on "unset" to work, but we need these variables # to be unset--not just set to an empty or harmless value--now, to # avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct # also avoids known problems related to "unset" and subshell syntax # in other old shells (e.g. bash 2.01 and pdksh 5.2.14). for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH do eval test \${$as_var+y} \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done # Ensure that fds 0, 1, and 2 are open. if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null then : eval 'as_fn_append () { eval $1+=\$2 }' else $as_nop as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null then : eval 'as_fn_arith () { as_val=$(( $* )) }' else $as_nop as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits # Determine whether it's possible to make 'echo' print without a newline. # These variables are no longer used directly by Autoconf, but are AC_SUBSTed # for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac # For backward compatibility with old third-party macros, we provide # the shell variables $as_echo and $as_echo_n. New code should use # AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. as_echo='printf %s\n' as_echo_n='printf %s' rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by isync $as_me 1.4.4, which was generated by GNU Autoconf 2.71. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" config_commands="$ac_config_commands" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Configuration commands: $config_commands Report bugs to the package provider." _ACEOF ac_cs_config=`printf "%s\n" "$ac_configure_args" | sed "$ac_safe_unquote"` ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"` cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ isync config.status 1.4.4 configured by $0, generated by GNU Autoconf 2.71, with options \\"\$ac_cs_config\\" Copyright (C) 2021 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' MKDIR_P='$MKDIR_P' AWK='$AWK' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) printf "%s\n" "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) printf "%s\n" "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) printf "%s\n" "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \printf "%s\n" "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX printf "%s\n" "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # # INIT-COMMANDS # AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "autodefs.h") CONFIG_HEADERS="$CONFIG_HEADERS autodefs.h" ;; "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;; "isync.spec") CONFIG_FILES="$CONFIG_FILES isync.spec" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test ${CONFIG_FILES+y} || CONFIG_FILES=$config_files test ${CONFIG_HEADERS+y} || CONFIG_HEADERS=$config_headers test ${CONFIG_COMMANDS+y} || CONFIG_COMMANDS=$config_commands fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_tt=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`printf "%s\n" "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` printf "%s\n" "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 printf "%s\n" "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`printf "%s\n" "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac ac_MKDIR_P=$MKDIR_P case $MKDIR_P in [\\/$]* | ?:[\\/]* ) ;; */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 printf "%s\n" "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t s&@MKDIR_P@&$ac_MKDIR_P&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 printf "%s\n" "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { printf "%s\n" "/* $configure_input */" >&1 \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 printf "%s\n" "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else printf "%s\n" "/* $configure_input */" >&1 \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi # Compute "$ac_file"'s index in $config_headers. _am_arg="$ac_file" _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" || $as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$_am_arg" : 'X\(//\)[^/]' \| \ X"$_am_arg" : 'X\(//\)$' \| \ X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$_am_arg" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'`/stamp-h$_am_stamp_count ;; :C) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 printf "%s\n" "$as_me: executing $ac_file commands" >&6;} ;; esac case $ac_file$ac_mode in "depfiles":C) test x"$AMDEP_TRUE" != x"" || { # Older Autoconf 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. # TODO: see whether this extra hack can be removed once we start # requiring Autoconf 2.70 or later. case $CONFIG_FILES in #( *\'*) : eval set x "$CONFIG_FILES" ;; #( *) : set x $CONFIG_FILES ;; #( *) : ;; esac shift # Used to flag and report bootstrapping failures. am_rc=0 for am_mf do # Strip MF so we end up with the name of the file. am_mf=`printf "%s\n" "$am_mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile which includes # dependency-tracking related rules and includes. # Grep'ing the whole file directly is not great: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ || continue am_dirpart=`$as_dirname -- "$am_mf" || $as_expr X"$am_mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$am_mf" : 'X\(//\)[^/]' \| \ X"$am_mf" : 'X\(//\)$' \| \ X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$am_mf" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` am_filepart=`$as_basename -- "$am_mf" || $as_expr X/"$am_mf" : '.*/\([^/][^/]*\)/*$' \| \ X"$am_mf" : 'X\(//\)$' \| \ X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X/"$am_mf" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` { echo "$as_me:$LINENO: cd "$am_dirpart" \ && sed -e '/# am--include-marker/d' "$am_filepart" \ | $MAKE -f - am--depfiles" >&5 (cd "$am_dirpart" \ && sed -e '/# am--include-marker/d' "$am_filepart" \ | $MAKE -f - am--depfiles) >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } || am_rc=$? done if test $am_rc -ne 0; then { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "Something went wrong bootstrapping makefile fragments for automatic dependency tracking. If GNU make was not used, consider re-running the configure script with MAKE=\"gmake\" (or whatever is necessary). You can also try re-running configure with the '--disable-dependency-tracking' option to at least be able to build the package (albeit without support for automatic dependency tracking). See \`config.log' for more details" "$LINENO" 5; } fi { am_dirpart=; unset am_dirpart;} { am_filepart=; unset am_filepart;} { am_mf=; unset am_mf;} { am_rc=; unset am_rc;} rm -f conftest-deps.mk } ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: " >&5 printf "%s\n" "" >&6; } if test -n "$have_ssl_paths"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Using SSL" >&5 printf "%s\n" "Using SSL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Not using SSL" >&5 printf "%s\n" "Not using SSL" >&6; } fi if test -n "$have_sasl_paths"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Using SASL" >&5 printf "%s\n" "Using SASL" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Not using SASL" >&5 printf "%s\n" "Not using SASL" >&6; } fi if test -n "$have_zlib"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Using zlib" >&5 printf "%s\n" "Using zlib" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Not using zlib" >&5 printf "%s\n" "Not using zlib" >&6; } fi if test "x$ac_cv_berkdb4" = xyes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Using Berkeley DB" >&5 printf "%s\n" "Using Berkeley DB" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Not using Berkeley DB" >&5 printf "%s\n" "Not using Berkeley DB" >&6; } fi if test $darwin = yes; then if test "x$have_macos_keychain" = xyes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Using macOS Keychain" >&5 printf "%s\n" "Using macOS Keychain" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Not using macOS Keychain" >&5 printf "%s\n" "Not using macOS Keychain" >&6; } fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: " >&5 printf "%s\n" "" >&6; } isync-1.4.4/ChangeLog0000644000175000001440000073653414152373733011366 000000000000002021-11-25 16:04 Oswald Buddenhagen * configure.ac: bump version 2021-11-26 10:53 Oswald Buddenhagen * configure.ac: modernize configure.ac 2021-12-01 10:25 Oswald Buddenhagen * src/sync.c: don't complain about concurrent flagging as deleted the result of propagating a deletion is flagging as deleted, so shut up if the only remote change is exactly that. 2021-11-26 22:05 Oswald Buddenhagen * src/sync.c: fix read beyond end of input in copy_msg_convert() the input isn't necessarily null-terminated (it currently is for imap, but not for maildir), so if the message ended somewhere within the header field name, we'd read beyond its end, which theoretically could cause a crash. no other adverse effects could result, as we'd stop processing such a broken message right afterwards. amends 70bad661. 2021-11-24 17:24 Oswald Buddenhagen * src/drv_imap.c: reject unreasonably long mailbox names from IMAP LIST this wasn't really a security problem, as the name mapping we actually do does not change the string length, and the iteration was already safe after the literal length fix, but it's still better to catch weird input. 2021-11-24 16:51 Oswald Buddenhagen * src/sync.c: reject messages that grow too large due to conversion that shouldn't really be a problem, as we have 2GB of headroom, and most growth would happen when sending an all-newlines message from maildir to imap (due to CR additions), which is mostly non-critical. but better safe than sorry. 2021-11-24 16:46 Oswald Buddenhagen * src/sync.c: report conversion errors directly in copy_msg_convert() that makes it easier to report various conditions without introducing separate error codes. 2021-11-24 16:22 Oswald Buddenhagen * src/drv_maildir.c: deal with oversized messages in maildirs don't try to read messages > 2G, as that will only lead to trouble down the line. this wouldn't have worked on linux anyway (we read in one chunk, and that is limited to (2^31 - 2^12) on all architectures), but on platforms were big reads work, this was a security problem if one synchronized other users' maildirs. as a minor fix on the side, we now also clip the reported message size, so MaxSize works for excessively big messages. 2021-11-24 18:21 Oswald Buddenhagen * src/drv_imap.c: CVE-2021-3657: reject excessively large IMAP literals we didn't limit the 32-bit size of literals so far, which, given that we use int-sized lengths & offsets, permitted all kinds of buffer overflows. malicious/compromised servers may have been able to exploit this. actual email senders would be constrained by size limits for delivered mails, and to cause more than a crash they'd have to predict the exact size of the final message. we now limit to 2GB, which, given that we use unsigned ints since e2d3b4d55 (v1.4.0), gives the handlers downstream plenty of headroom. an alternative would have been using 64-bit offsets, but this seems like major overkill, even if IMAP4rev2 recently mandated it (we talk only IMAP4rev1, so we can ignore it). 2021-11-22 19:57 Oswald Buddenhagen * src/sync.c: CVE-2021-44143: don't overflow heap on messages without headers when a broken/compromised/malicious server gives us a message that starts with an empty line, we'd enter the path for inserting a pristine placeholder subject, for which we unfortunately didn't actually allocate space (unless MaxSize is in use and the message exceeds it). note that this cannot be triggered by merely receiving a crafted mail with no headers (yes, it's actually possible to send such a thing), as the delivery of mails adds plenty of headers. amends 70bad661. 2021-07-29 11:14 Oswald Buddenhagen * configure.ac: bump version 2021-06-21 09:35 Oswald Buddenhagen * src/drv_maildir.c: limit maildir nesting depth this is a cheap way to catch symlink loops. 10 seems like a reasonable limit, as it's unlikely that anyone would be able to actually work with such a deeply nested mailbox tree. fixes debian bug #990117. 2021-06-11 15:56 Oswald Buddenhagen * src/drv_imap.c: enable embedding arbitrarily long strings into IMAP commands the AUTHENTICATE command may get insanely long for GSSAPI when SASL-IR is available. instead of growing the buffers each time someone hits the limit (as done in f7cec306), remove the limitation altogether. imap_vprintf() still contains a fixed-size buffer which could overflow when really long strings (e.g., mailbox names) need to be quoted. this seems very unlikely, so we'll deal with it if someone actually hits it. REFMAIL: 87sg1qxdye.fsf@cern.ch 2021-06-03 09:07 Oswald Buddenhagen * configure.ac: bump version 2021-06-03 09:02 Oswald Buddenhagen * configure.ac: bump version 2021-04-14 14:58 Oswald Buddenhagen * src/drv_imap.c: CVE-2021-3578: fix handling of unexpected APPENDUID response code if the code was sent in response to anything but a STORE, we'd overwrite a data pointer in one of our imap_cmd subclasses, an allocator data structure, or the start of the next allocation, with an int that was completely under the server's control. it's plausible that this could be exploited for remote code execution. to avoid this, we could ensure that the object is of the right type prior to casting, by using a new flag in the parameter block. but it's easier to just dispose of the out_uid field altogether and reuse the uid field that is present in the parameter block anyway, but was used only for FETCH commands so far. this problem was found by Lukas Braun using a fuzzer. 2021-04-14 14:52 Oswald Buddenhagen * src/drv_imap.c: don't crash on malformed CAPABILITY responses amends 95a83c822. this problem was found by Lukas Braun using a fuzzer. 2021-03-19 17:21 Oswald Buddenhagen * src/: driver.h, drv_imap.c, drv_maildir.c: tolerate INBOX mis-casing in Path while it's technically reasonable to expect the user to match the server's casing of INBOX if they set Path, this might come as a surprise to those who know that the IMAP INBOX is case-insensitive. so tolerate any casing instead. as a minor side effect, we'd now even be able to deal with a server using different casing in NAMESPACE and LIST. 2021-02-21 20:24 Oswald Buddenhagen * configure.ac: bump version 2021-02-20 21:52 Oswald Buddenhagen * src/sync.c: make UIDVALIDITY recovery more strict about vanished messages in particular, this covers the case of a mailbox being replaced with an empty new one, which would subsequently lead to the opposite end being emptied as well, which would typically be undesired. also add plenty of comments. 2021-02-20 21:52 Oswald Buddenhagen * src/sync.c: improve error messages about irrecoverably changed UIDVALIDITY don't print the actual values, which are meaningless technicalities to the average user, and can be obtained separately for debugging if really necessary. also, fix the omission of the affected mailboxes from one of the messages. 2021-02-14 19:42 Oswald Buddenhagen * src/drv_imap.c: CVE-2021-20247: reject funny mailbox names from IMAP LIST/LSUB in particular, '..' in the name could be used to escape the Path/Inbox of a Maildir Store, which could be exploited for stealing or deleting data, or staging a (mild) DoS attack. 2021-02-14 22:37 Oswald Buddenhagen * src/drv_imap.c: be more tolerant of formally malformed response codes fastmail sends flags containing ']' in PERMANENTFLAGS, which is formally illegal. however, if we parse the embedded list before looking for the response code's closing ']', things work out fine. as a side effect we won't complain about similarly or completely malformed response codes we don't recognize at all, which may or may not be considered an improvement ... 2021-02-14 22:06 Oswald Buddenhagen * src/drv_imap.c: fix bogus continuation of IMAP list parsing on error, parse_imap_list() needs to reset the nesting level in the state, as imap_socket_read() uses that as an indicator whether list parsing is ongoing. 2021-02-14 20:25 Oswald Buddenhagen * src/drv_imap.c: accept unsolicited FETCH responses (without payload) after all while the spec says that the server SHOULD not send FETCH responses about STORE FLAGS when .SILENT is used, at least gmail and fastmail seem to do it nonetheless. also, in case of concurrent flag updates on the affected messages such responses can be legitimately sent. in earlier versions of mbsync this would lead to duplicate messages piling up in the store, though that would pose no problem at that point. 2021-02-14 22:46 Oswald Buddenhagen * configure.ac: bump version 2021-02-07 19:26 Nihal Jere * configure.ac, src/common.h, src/util.c: use correct header In POSIX, poll() should be accessible using , although most implementations keep to avoid breakage. This fixes some warnings when building on musl. 2021-02-03 13:44 Oswald Buddenhagen * configure.ac: bump version 2021-02-03 13:25 Oswald Buddenhagen * src/drv_imap.c: unbreak handling of 'INBOX.' NAMESPACE again INBOX matching must not prevent prefix (namespace) stripping, as INBOX may be the namespace. amends 04fc586e7. REFMAIL: 186391612191752@vla1-ea7e194e8506.qloud-c.yandex.net 2021-01-03 18:39 Anton Khirnov * src/drv_imap.c: Set authentication id for the SASL EXTERNAL mechanism The SASL library will refuse to use the EXTERNAL module when no auth id is set a priori. Tested to work with Dovecot, using TLS client certificates for authentication. 2021-01-05 18:45 Oswald Buddenhagen * src/drv_imap.c: improve SASL error messages provide context, and remove the redundant numeric codes. 2021-01-05 18:44 Oswald Buddenhagen * src/drv_imap.c: tune SASL-related comments - add explanations to the callbacks - remove bogus comment - EXTERNAL can be in fact missing (when no authentication id is set) 2021-01-01 13:46 Oswald Buddenhagen * src/util.c: save errno in sys_error() the print functions prior to perror() might otherwise clobber it. 2020-12-18 13:33 Oswald Buddenhagen * src/run-tests.pl: autotest: remove unused boxname parameter from printbox() 2020-12-18 13:31 Oswald Buddenhagen * src/run-tests.pl: autotest: pass containers by reference this makes function prototypes a lot more useful for parameter checking. 2020-12-14 22:16 Oswald Buddenhagen * src/: common.h, driver.h, drv_imap.c, drv_proxy.c, drv_proxy_gen.pl, main.c, run-tests.pl: add forced async mode to proxy driver to test async operation of the syncing core while using the synchronous maildir driver, we add a mode to the proxy driver where it queues callback invocations to the next main loop iteration. 2020-12-14 13:08 Oswald Buddenhagen * src/drv_proxy.c: localize a variable more appropriately 2020-12-16 12:49 Oswald Buddenhagen * src/: main.c, run-tests.pl: consolidate testing options behind common switch don't pollute the namespace with random uppercase switches. instead, have a new -T switch with suboptions, just like -D. 2020-12-17 14:53 Oswald Buddenhagen * configure.ac, src/common.h, src/driver.h, src/drv_imap.c, src/drv_maildir.c, src/drv_proxy.c: introduce new inheritance model based on C11 anonymous structs the struct declarations got uglier, but their usage requires a lot fewer explicit references to the parent struct (though some are added where using the derived struct is more practical now). we also use something i'd term "covariant members": derivatives of store_t also reference derivatives of store_conf_t, etc., which drastically cuts down the number of casts. fwiw, to achieve this with "proper" inheritance in C++, we'd use covariant getter functions which hide the still existing casts. C11 is almost a decade old now, and compilers supported that feature even longer than that, so i don't expect this to be a problem. 2020-12-17 21:03 Oswald Buddenhagen * src/: drv_proxy.c, drv_proxy_gen.pl: add some error checking to proxy template processor debugging is a lot easier when the unconsumed (and therefore likely mistyped) replacements are complained about. 2020-12-17 19:14 Oswald Buddenhagen * src/drv_proxy_gen.pl: handle indentation in proxy driver template code more flexibly use the indentation of the placeholder, not the replacement. this doesn't matter right now, as all placeholders are indented by one step, but that will change soon. the indent function cannot be inlined into the substitution, as for some reason ^ then matches the end of the string, not the embedded line starts (with perl v5.32). also, $1 needs to go into a temporary anyway. 2020-12-14 22:24 Oswald Buddenhagen * src/common.h: make FALLTHROUGH work with qtcreator's code model the code model inspector claims that __GNUC__ is 10, but the #if works only with >= 4, which is plain wrong. so just handle clang explicitly. 2020-12-12 13:56 Oswald Buddenhagen * src/mbsync.1: improve docu for {Pass,User}Cmd 2020-11-29 12:47 Oswald Buddenhagen * configure.ac: fix build with macOS keychain support we use symbols from CoreFoundation directly, so we need to link it explicitly. amends 198ca65b. 2020-10-05 11:16 Oswald Buddenhagen * src/mbsync.1: improve wording in man page 2020-10-05 11:15 Oswald Buddenhagen * src/drv_imap.c: streamline init of type & name in imap_parse_store() 2020-10-05 11:05 Oswald Buddenhagen * src/: config.c, driver.c, driver.h, drv_imap.c, drv_maildir.c: make complaints about unrecognized keywords more verbose tell the user in what section the keyword appeared, as that may help spotting mistakes like stray empty lines. 2020-10-05 10:35 Oswald Buddenhagen * src/config.c: complain about global options following sections while harmless for most options, such usage is counter to the documentation, and actually breaks CopyArrivalDate, MaxMessages, and ExpireUnread. 2020-10-05 10:31 Oswald Buddenhagen * src/config.c: make exit from parsing Group sections less convoluted this is a de-optimization, but it makes the code consistent with the other sections (which do not use the shortcut due to having to post-process the data or being encapsulated by a function call). 2020-10-05 09:56 Oswald Buddenhagen * src/: config.c, config.h, main.c: remove the -cT option it was another vestige from the compat wrapper. amends cbac8aa75. 2020-08-05 18:58 Oswald Buddenhagen * src/drv_imap.c: improve error handling in post-STORE UIDNEXT fallback that's mostly hypothetical, but let's not make assumptions. this also adds EXPUNGE response handling to make total_msgs reliable. in principle, this affects the post-SELECT UIDNEXT fallback as well, but there the racing window is so short that this barely improves anything. amends 94022a67. 2020-08-05 17:48 Oswald Buddenhagen * src/drv_imap.c: fix UIDNEXT query vs. concurrent imap_fetch_msg() the uidnext query following message stores can be interleaved with message fetches. that means that we cannot rely on the 1st command in flight being that query. but instead of iterating over all commands in flight, move the uidnext query flag to imap_store (and make sure to check for the presence of a message body before testing it) - this avoids the loop and an extra byte in every command. this also makes it clear that the query is mutually exclusive with loading messages (the untagged responses are not distinguishable). 2020-08-05 16:06 Oswald Buddenhagen * src/: driver.h, drv_imap.c: make item tracking in parse_fetch_rsp() more uniform amends 67ea5bea7 & a5a8783ea. 2020-08-05 15:43 Oswald Buddenhagen * src/drv_imap.c: delay allocation of msgdata.msgid field this allows us to simplify the exit path of parse_fetch_rsp(). 2020-08-05 15:36 Oswald Buddenhagen * src/drv_imap.c: fix invalid free() in error path the tuid isn't actually allocated - it's a pointer into the raw data. amends a5a8783e. 2020-08-05 15:29 Oswald Buddenhagen * src/drv_imap.c: remove redundant zero initializations we already use calloc(). amends 130664b6. 2020-08-04 07:08 Oswald Buddenhagen * src/drv_imap.c: de-duplicate exit paths of imap_alloc_store() 2020-08-04 07:06 Oswald Buddenhagen * src/drv_imap.c: don't unnecessarily re-initialize some members of imap_store ... when recycling server connections. 2020-08-03 22:23 Oswald Buddenhagen * src/: drv_maildir.c, sync.c: use more appropriate return value in driver_t::select_box() don't say DRV_CANCELED when it's really DRV_STORE_BAD, as apart from being just wrong, it lead to the confusing effect of canceling a store as the result of a supposed cancellation of the same store. 2020-07-29 18:23 Oswald Buddenhagen * src/: common.h, socket.c, socket.h, util.c: handle CertificateFile more cleanly properly distribute the certificates between the SSL context's trust store and our host cert list. as a drive-by, clean up some nasty type casts at the cost of including a second OpenSSL header into socket.h. 2020-07-28 14:14 Oswald Buddenhagen * src/: drv_imap.c, drv_proxy.c: actually implement imap_commit_cmds() delay reporting success of STORE FLAGS until a subsequent CHECK succeeds. this fixes (inverse flag change propagation) and (deletes not being propagated) after an interruption due to prematurely logged flag updates. 2019-12-29 13:37 Oswald Buddenhagen * src/: driver.h, drv_imap.c, drv_maildir.c, mbsync.1, run-tests.pl, sync.c: create placeholders for messages over MaxSize this is vastly more useful than just omitting the messages with no indication at all. 2019-11-25 19:55 Oswald Buddenhagen * src/: run-tests.pl, sync.c: don't rewrite state gratuitously delay the creation of the new state and journal until there is actually something interesting to write. this saves some cpu cycles and prolongs ssd life a whee bit. 2019-11-17 18:45 Oswald Buddenhagen * src/: driver.h, drv_imap.c, run-tests.pl, sync.c, sync.h: add/fix/de-duplicate comments 2019-12-29 13:41 Oswald Buddenhagen * src/sync.c: de-duplicate updating of uid in sync records 2020-07-20 18:53 Oswald Buddenhagen * src/: run-tests.pl, sync.c: do away with newmaxuid now that expiration order is determined by a single loop ordered by far-side UIDs, it is no longer necessary to accurately track the highest seen UID. as a side effect, this fixes a problem reported (way too long ago) by Yuri D'Elia: we failed to up newmaxuid for messages we produced ourselves, so we would keep enumerating the same messages until we also propagated externally generated messages from that mailbox - which might have been never for the server side of archive/trash mailboxes. 2020-07-16 12:47 Oswald Buddenhagen * src/sync.c: make expiration loops solely far-side-driven we can do that, as unpaired near-side messages are ignored anyway. this mildly changes expiration order, as near-side messages that existed for a long time but were propagated much later will be expired later. however, that has no practical relevance. 2020-07-16 11:08 Oswald Buddenhagen * src/sync.c: don't forget to skip dead messages on far side during expiration this is mostly theoretical, as at this point no updates to the message list can have actually happened. but it's future-proof and consistent with the near-side loop. 2020-07-12 15:21 Oswald Buddenhagen * src/sync.c: streamline counting of currently pushed messages wrt. expiration don't count them as alive just to ignore them in the next step. 2020-07-08 12:37 Oswald Buddenhagen * src/sync.c: re-nest conditions for syncing new messages this makes the logic easier to follow and document in place. also, make the comments actually match reality. 2020-07-21 14:10 Oswald Buddenhagen * src/sync.c: handle messages which are newly doomed after an interruption we already didn't propagate messages which would be instantly expunged from the target, but failed to cancel propagations that were already scheduled before we got interrupted. this matters a bit when the resumption happens significantly later than the initial attempt, giving the user time to mark messages on the source as deleted. 2020-07-11 14:21 Oswald Buddenhagen * src/sync.c: remove redundant condition the 'pending' and 'skipped' sync record states are mutually exclusive with having a complementary message, so there is no point in testing it explicitly. amends bd5fb6ff. 2019-12-29 10:52 Oswald Buddenhagen * src/: driver.h, drv_imap.c, drv_maildir.c, drv_proxy.c, sync.c: fix loading of some messages' sizes in some partial sync scenarios we need to pass a different "boundary" UID to driver_t::load_box() for every OPEN_* flag that queries a partial range: - OPEN_FIND refers to messages newer than all we know about - OPEN_OLD_IDS refers to messages which are paired - OPEN_{OLD,NEW}_SIZE refers to messages (not) above the committed boundary of already propagated messages we treated the 3rd like the 2nd, which was just wrong - the actual boundary may be lower or higher, so we'd produce wrong results when MaxSize was set and only one of New and ReNew was requested. 2020-07-22 17:44 Oswald Buddenhagen * src/: config.c, config.h, main.c, mbsync.1, mbsyncrc.sample, run-tests.pl, sync.c, sync.h: deprecate master/slave terminology the underlying metaphor refers to an inhumane practice, so using it casually is rightfully offensive to many people. it isn't even a particularly apt metaphor, as it suggests a strict hierarchy that is counter to mbsync's highly symmetrical mode of operation. the far/near terminology has been chosen as the replacement, as it is a natural fit for the push/pull terminology. on the downside, due to these not being nouns, a few uses are a bit awkward, and several others had to be amended to include 'side'. also, it's conceptually quite close to remote/local, which matches the typical use case, but is maybe a bit too suggestive of actually non-existing limitations. the new f/n suffixes of the -C/-R/-X options clash with pre-existing options, so direct concatenation of short options is even less practical than before (some suffixes of -D already clashed), but doing that leads to unreadable command lines anyway. as with previous deprecations, all pre-existing command line and config options keep working, but yield a warning. the state files are silently upgraded. 2020-07-04 14:13 Oswald Buddenhagen * src/sync.c: purge handling of pending sync entries from state file these cannot actually end up in the committed state. amends bd5fb6ff. 2020-07-08 20:16 Oswald Buddenhagen * src/: common.h, sync.c: wrap jFprintf()+debug() into a macro this ensures that everything that is logged to the journal also appears in the debug output, and it makes the code less noisy. 2019-11-27 16:13 Oswald Buddenhagen * configure.ac, src/Makefile.am, src/drv_imap.c, src/mbsync.1, src/mbsyncrc.sample: add option to get password from macOS Keychain this is better than using PassCmd, as it allows the keychain manager to identify the calling process and therefore use a selective whitelist. unlike in the now removed example, we use an "internet password" for the imap protocol, rather than a "generic password" - this seems more appropriate. based on a patch by Oliver Runge 2019-11-26 11:17 Oswald Buddenhagen * src/: drv_imap.c, mbsync.1: add ability to script IMAP user query It was already possible to retrieve passwords from arbitrary commands. But this goes only half the way to allowing automated derivation of login credentials, as some environments may also have different user names based on the system. Therefore, add the UserCmd option to complement PassCmd. Based on a patch series by Patrick Steinhardt 2019-11-22 16:50 Oswald Buddenhagen * src/drv_imap.c: de-duplicate FETCH response data item traversal somewhat 2019-11-22 16:49 Oswald Buddenhagen * src/drv_imap.c: complain about malformed item names in FETCH responses 2019-11-22 15:54 Oswald Buddenhagen * src/drv_imap.c: re-nest parse_fetch_rsp() prefer early exits over else branches, which is easier to follow. 2019-11-11 15:32 Oswald Buddenhagen * src/drv_imap.c: extract parse_fetched_flags() from parse_fetch_rsp() 2019-11-11 15:18 Oswald Buddenhagen * src/drv_imap.c: extract parse_fetched_header() from parse_fetch_rsp() 2019-11-11 16:24 Oswald Buddenhagen * src/drv_imap.c: handle bogus IMAP FETCH responses more robustly don't use assert()s when the error condition can stem not only from errors in mbsync's logic, but also from the IMAP stream being corrupted. amends 72be55b0e. REFMAIL: 20191021233411.55ctuvslkfqf2pna@koblih.localdomain 2019-11-11 13:29 Oswald Buddenhagen * src/drv_imap.c: sanitize error handling in IMAP FETCH response processing abort on actual error conditions (protocol errors) and downgrade the rest to warnings. REFMAIL: 20191102164509.dxayakg3hrmozjnm@carbon 2019-11-11 12:51 Oswald Buddenhagen * src/drv_imap.c: centralize disposal of parsed IMAP lists makes the code less cluttered, and it's harder to introduce leaks. this has the hypothetical disadvantage that due to freeing being delayed, the peak memory usage would rise significantly if we chained to another parse_list() call which produces a big list while already holding a big list, but that isn't the case anywhere. 2019-11-11 12:41 Oswald Buddenhagen * src/drv_imap.c: fully decompose NAMESPACE response early on that way the code becomes clearer, and we don't keep useless nodes in memory. 2019-11-10 16:13 Oswald Buddenhagen * src/drv_imap.c: don't store 'shared' and 'other' namespaces they are never used anyway, and aren't going to be (because configuring that would be more annoying than just specifying Path manually). 2019-11-16 15:00 Oswald Buddenhagen * src/: common.h, socket.c, socket.h, util.c: drop redundant conn->writing member this information is already encoded in the socket notifier's config. 2019-11-15 19:20 Oswald Buddenhagen * src/: common.h, util.c: rewrite nonsensical struct packing magic this couldn't have possibly worked - the alignment also determines the sizeof, thus defeating the intent of the packing. 2019-11-15 19:21 Oswald Buddenhagen * configure.ac: modernize list of gcc warning flags somewhat 2019-07-28 18:50 Oswald Buddenhagen * src/: common.h, config.c, drv_imap.c, drv_maildir.c, drv_proxy_gen.pl, main.c, mdconvert.c, socket.c, socket.h, sync.c, util.c: consistently use NULL for null pointers makes the code noisier, but also somewhat more expressive. 2020-07-08 15:27 Oswald Buddenhagen * src/: common.h, config.c, config.h, driver.c, driver.h, drv_imap.c, drv_maildir.c, drv_proxy.c, main.c, socket.c, socket.h, sync.c, sync.h, util.c: fix lots of sign conversion warnings ... by making a lot of objects unsigned, and some signed. casts which lose precision and change the sign in one go (ssize_t and time_t to uint on LP64) are made explicit as well. 2019-07-28 20:10 Oswald Buddenhagen * src/: drv_imap.c, drv_maildir.c, sync.c, util.c: make some narrowing of integers explicit this does specifically *not* cover about a bazillion warnings about size_t being shrunk to uint - these make no sense given the expected data set size. 2019-07-28 19:24 Oswald Buddenhagen * src/: common.h, config.c, config.h, sync.c, util.c: shrink some data at the source to avoid subsequent narrowing 2019-07-28 19:13 Oswald Buddenhagen * src/: drv_maildir.c, main.c, socket.c, sync.c, sync.h, util.c: constness fixes add missing const qualifications, and add "const cast" suppressions where unavoidable. 2019-07-28 18:54 Oswald Buddenhagen * src/: config.c, drv_imap.c, main.c, sync.c: make more objects static 2019-07-28 17:52 Oswald Buddenhagen * src/: common.h, drv_imap.c, main.c, sync.c, util.c: add some ATTR_* (mostly) mostly ATTR_PRINTFLIKE(*, 0) for functions with a va_list argument. also, one ATTR_NORETURN and one ATTR_UNUSED, both on functions. also, an explicit suppression for a format string stored in a variable. 2020-08-04 14:54 Oswald Buddenhagen * src/: common.h, drv_maildir.c, util.c: turn maildir_again() into a proper varargs function this is mostly to work around the fact that both gcc and clang won't accept the format string declaration (i.e., will complain with -Wformat-nonliteral) if the *called* function does not actually take a va_list. on the upside, it makes one caller cleaner. yay ... 2019-11-26 15:18 Oswald Buddenhagen * src/: drv_imap.c, socket.c, socket.h: remove support for SSLv3 it's insecure and default builds of openssl don't include it any more. 2019-11-26 15:05 Oswald Buddenhagen * src/: drv_imap.c, mbsync.1, socket.c, socket.h: add support for (disabling) TLS v1.3 this is actually potentially counterproductive, as people who have set SSLVersions and fail to adjust it will _lose_ tls 1.3 support. however, without the option being there, people (incorrectly) believe that tls 1.3 is not supported. 2019-11-26 14:49 Oswald Buddenhagen * src/: drv_imap.c, mbsync.1: Add option to use IMAP LSUB instead of LIST Based on patch by Cedric Ware 2011-06-02 17:41 Oswald Buddenhagen * src/drv_imap.c: IMAP: reject unqualified non-uppercased INBOX spellings otherwise the server would interpret it as INBOX contrary to our expectations, which might lead to moderately surprising effects. if you really want to sync your ~/maildir/inbox to the IMAP INBOX, specify it as the Maildir Store's Inbox. 2019-11-09 18:47 Jaroslav Suchanek * src/: drv_imap.c, mbsync.1, socket.c, socket.h: Add support for specifying cipher string used for ssl connection Some distributions (e.g. Fedora) added support for system wide crypto policies. This is supported in most common crypto libraries including OpenSSL. Applications can override this policy using their own cipher string. This commit adds support for specifying the cipher string in the mbsync configuration. For example, to exclude Diffie-Hellman, the user can specify CipherString "DEFAULT:!DH" in the IMAP Account's configuration. 2019-12-29 11:34 Oswald Buddenhagen * src/sync.c: set sync record's flags only after propagating new message this is semantically cleaner, and fixes storing the flags in the rare case that flags are not being synced and the target is not being expunged, as in this case flags are queried only during the actual propagation. 2020-07-07 19:14 Oswald Buddenhagen * src/sync.c: atomize & document conditions in load() exception list construction 2019-12-29 11:31 Oswald Buddenhagen * src/sync.c: de-noise msg_copied() and flags_set() somewhat assign temporary srec object instead of always spelling out the indirection. 2019-12-03 12:06 Oswald Buddenhagen * src/sync.c: de-noise initialization of sync records use calloc() instead of malloc(). 2019-11-16 16:14 Oswald Buddenhagen * src/: drv_imap.c, socket.c, socket.h: rename socket_expect_read() => socket_expect_activity() ... to better reflect its (mostly new) function. 2019-11-16 13:17 Oswald Buddenhagen * src/socket.c: re-nest conditions in socket_fd_cb() conn->state == SCK_STARTTLS implies conn->ssl != NULL. 2019-07-28 11:36 Oswald Buddenhagen * src/socket.c: move state assignment to a more natural place ... so it's right next to the related callback assignment. 2019-11-22 19:10 Oswald Buddenhagen * src/drv_proxy.c: de-noise -Dd output somewhat drop commas and left-align fields in message lists. 2020-07-08 11:45 Oswald Buddenhagen * src/: driver.h, drv_imap.c, drv_maildir.c, drv_proxy.c, sync.c: fix signedness issues surrounding UIDs amends bb632d1c. 2019-11-22 20:02 Oswald Buddenhagen * src/util.c: make find_uint_array() never create negative indices 2019-11-15 19:04 Oswald Buddenhagen * src/drv_maildir.c: centralize "const cast" in make_key() 2019-07-28 18:42 Oswald Buddenhagen * src/: common.h, drv_imap.c: fix strftime() format string warning properly the workaround for -Wformat triggered -Wformat-nonliteral in turn. so instead go back to using pragmas and add a proper gcc version check. this also works with clang - mostly for qt-creator's code model, which is clang-based. amends/reverts 55e65147. 2019-07-28 20:31 Oswald Buddenhagen * src/common.h: don't use reserved identifier pattern in stringify() 2019-11-11 21:42 Oswald Buddenhagen * src/main.c: don't leak the channel list after all unlike the actual configuration data, it's not kept in global variables, so it shows up in memcheck. amends 1de3ecd88. 2019-11-11 21:32 Oswald Buddenhagen * src/main.c: don't leak box list from the command line we also free the box list obtained from IMAP, so there isn't a real reason not to do that for one from the command line. amends 1de3ecd88. 2020-07-22 12:18 Oswald Buddenhagen * src/drv_maildir.c: actually implement maildir_get_uidnext() the assumption was that this wouldn't be needed, as maildir_store_msg() reliably delivers a UID. however, if we crash right before the callback can record that UID, we'd still use OPEN_FIND in the next run, which requires the saved next UID. 2020-07-21 15:16 Oswald Buddenhagen * src/drv_maildir.c: get rid of maildir_find_new_msgs() stub a failed assertion isn't any better than a clean segfault with an obvious backtrace. 2020-06-14 11:16 Oswald Buddenhagen * src/drv_maildir.c: Maildir: fix setting flags on messages without ":2," part this is mostly hypothetical, as all messages i've encountered actually have it even if no flags are set on them. 2019-11-24 09:54 Oswald Buddenhagen * Makefile.am: give the coverity build result archive a more descriptive name 2020-04-02 18:39 Oswald Buddenhagen * src/run-tests.pl: autotest: use symbolic message subjects ... instead of numbers. otherwise there is too much confusion with UIDs. 2020-04-03 08:43 Oswald Buddenhagen * src/run-tests.pl: autotest: re-order mailbox contents according to UIDs ... instead of subjects, because that's way more natural and thus less confusing. 2020-04-03 10:18 Oswald Buddenhagen * src/run-tests.pl: autotest: re-organize mailbox storage by UID an effect of 7ce658d is that we can index messages by UID rather than content (or more specifically, subject). apart from being cleaner, it allows duplicated subjects. 2020-04-03 09:21 Oswald Buddenhagen * src/run-tests.pl: autotest: assume that each message has a UID followup to 7ce658d14. 2019-12-29 11:06 Oswald Buddenhagen * src/run-tests.pl: autotest: show the right state file after idempotence test failure amends efd72b85. 2019-12-29 10:59 Oswald Buddenhagen * src/run-tests.pl: autotest: fix prototype of ckbox() 2019-12-29 10:59 Oswald Buddenhagen * src/run-tests.pl: autotest: create the temp dir in $TEMP on modern systems, this makes it likely to end up on tmpfs, which is a lot faster and ssd-friendlier. the symlink is not deleted at the end, to minimize fs churn. that means it will be dangling after a reboot, which gets fixed in the next run. 2020-08-04 12:44 Oswald Buddenhagen * configure.ac: bump version 2020-08-04 09:17 Oswald Buddenhagen * src/socket.c: fix version comparison in LibreSSL conditional the operator was exactly inverted. that means that it actually wouldn't compile with both older versions (that needed the aliases) and potentially new versions (that will hide the data members - still not the case as of 3.2). amends 8a40554f0. 2020-08-04 08:10 Oswald Buddenhagen * src/drv_imap.c: fix re-using server connections for new stores we failed to reset the box list pointer after freeing it, which would lead to a crash. we also failed to reset the listing status, which would lead to malfunction if we hadn't already crashed. this inlines imap_cleanup_store(), as there isn't much value in keeping it. the message list is already freed when disowning the store anyway. 2020-08-03 10:39 Oswald Buddenhagen * src/drv_proxy.c: don't crash in proxy_invoke_bad_callback() we need to hold a ref to the proxy store, as after the bad_callback() it's otherwise likely gone. 2020-07-27 20:48 Oswald Buddenhagen * src/: socket.c, socket.h: fix simultaneously connecting to multiple hosts in non-IPv6 builds we need to deep-copy the struct hostent data, as otherwise the concurrent connects will overwrite each other's lookup results. this is a rather hypothetical fix, as the bug currently affects only channels connecting two IMAP accounts, and only if the first host's first address asynchronously fails to connect. 2020-07-27 22:28 Oswald Buddenhagen * src/drv_imap.c: increase PassCmd output buffer even more apparently, some XOAUTH2 tokens are at 2.4K already, so make it 8K to be *really* safe for a while. REFMAIL: <20200716000515.GA2111668@lysator.liu.se> 2020-08-02 18:05 Oswald Buddenhagen * src/mbsync.1: unbreak CertificateFile documentation the file may in fact contain CA certs. amends 7d9d3e15. 2020-07-08 09:42 Oswald Buddenhagen * configure.ac: bump version 2019-12-29 11:59 Oswald Buddenhagen * src/sync.c: fix propagation of flagged oversized messages ... when not syncing flags and the target is not being expunged, as in that case flags were not queried in time. 2019-11-24 09:54 Oswald Buddenhagen * src/compat/: config.c, main.c: fix printf length arguments on lp64 found by coverity. 2019-09-09 16:47 Oswald Buddenhagen * src/: drv_imap.c, drv_maildir.c: handle case-insensitivity of IMAP's INBOX this is relevant only when listing an IMAP Store's contents, as that's the only place where we aren't imposing the spelling ourselves. we need to be careful not to treat our own canonical (prefix-stripped and always slash-delimited) box names like that; codify that in comments. this reveals that commit 6f2160f1 may be deemed to have been incorrect - the TODO item was ambiguous, and could quite possibly have meant this fix. unsurprisingly, 380ccdd4 re-introduced it with more explicit wording. 2019-11-23 12:51 Oswald Buddenhagen * src/drv_imap.c: catch server's failure to FETCH * the query is untypical enough to have caused problems with davmail (when we still used *:*) and mailo.com (until it got fixed), so better check that the result (not) returned by the server makes sense. 2019-11-16 16:14 Oswald Buddenhagen * src/socket.c: don't timeout while uploading big messages we did already set up the timeout when starting to send commands, but so far we did not reset it when succeeding to send out data. rectify that. REFFAIL: 87sgy92we3.fsf@jnanam.net 2019-12-03 12:00 Oswald Buddenhagen * src/main.c: make -DC work with yama ptrace protection 2019-11-22 20:00 Oswald Buddenhagen * src/: drv_maildir.c, util.c: fix overflows in uint comparisons 2019-11-27 16:55 Oswald Buddenhagen * src/: compat/isync.1, mbsync.1: fix roff abuse in man pages ".." is not valid. use "." instead, as recommended by groff_man(7). this also necessitated adjusting the markup of the license blurbs. 2019-11-18 17:57 Oswald Buddenhagen * src/mbsync.1: improve documentation of the server certificate related options 2020-02-28 11:10 Oswald Buddenhagen * Makefile.am: re-generate ChangeLog only if it's newer than the git index otherwise, we'd re-generate it during 'install' as well. note that this does not work with new-style git worktrees, where .git is only a file - but there the log generation itself already doesn't work anyway. 2019-11-18 15:30 Oswald Buddenhagen * README: update build requirements in particular, mention perl-related things, which might not be immediately obvious. 2020-07-01 16:25 Oswald Buddenhagen * src/main.c: mention --remove in --help output amends d9a983a. 2019-11-23 12:30 Oswald Buddenhagen * src/drv_imap.c: fix UIDNEXT error message 2020-01-08 17:22 Oswald Buddenhagen * src/: driver.h, drv_imap.c, drv_maildir.c, sync.c: don't try to propagate flags the target store does not support $Forwarded is not standard, so it will most likely fail with mailboxes that do not support keywords. amends c4d7f018. 2019-12-28 16:45 Oswald Buddenhagen * src/driver.h: rename F_PASSED => F_FORWARDED the flag names are supposed to reflect the IMAP names (that's why their #defines are followed by comments with the Maildir names). amends c4d7f018. 2019-07-28 11:33 Oswald Buddenhagen * src/socket.c: fix error handling of SSL_set_tlsext_host_name() it is not one of the functions to be checked with SSL_get_error(). amends 17babc169. 2019-07-28 10:11 Oswald Buddenhagen * src/socket.c: error-check more openssl function calls 2019-07-28 09:35 Oswald Buddenhagen * src/: common.h, socket.c: attempt to improve ssl error handling (again) the error queue may contain multiple errors, so make sure to drain it completely. also, don't try to fall back to errno in case of SSL_ERROR_SSL. 2019-07-28 10:02 Oswald Buddenhagen * src/socket.c: modernize ssl context init with openssl 1.1+, use TLS_client_method() instead of the deprecated SSLv23_client_method(). 2019-07-28 09:46 Oswald Buddenhagen * src/socket.c: fix leak of openssl X509 objects SSL_get_peer_certificate() increments the refcount of the object. 2019-09-10 11:14 Oswald Buddenhagen * configure.ac: fix libcrypto detection in openssl 1.1+ without pkg-config CRYPTO_lock() was removed. test for X509_cmp() instead, which we actually use. inspired by report from FX . 2019-09-10 11:00 Oswald Buddenhagen * src/mbsync.1: wording fixes in mbsync.1 inspired by Ulrich Ölmann . 2019-08-30 11:13 Oswald Buddenhagen * configure.ac, isync.spec.in: purge vestiges of the compat wrapper amends cbac8aa75. 2019-08-18 08:38 Caspar Schutijser * src/socket.c: Do not crash when using Tunnel in an IPv6-enabled build socket_connected() is also called on the tunnel pipe. amends 3ceb55310. 2019-07-09 18:51 Dmitry Torokhov * src/drv_imap.c: Bump up PassCmd buffer size to 2KiB While ordinary passwords are rarely longer than 80 bytes, XOAUTH2 tokens easily exceed this limit. Let's bump it up to 2K to be really safe. 2019-05-28 15:27 Oswald Buddenhagen * src/drv_imap.c: fix parsing of NIL hierarchy delimiters in IMAP LIST responses a server which does not support hierarchical mailboxes (e.g., seznam.cz as of oct 2018) can legitimately send NIL (rather than an empty string). 2019-05-28 13:44 Oswald Buddenhagen * configure.ac: make output of perl check more tidy amends c75001aa. 2019-03-10 10:30 Oswald Buddenhagen * src/drv_imap.c: fix spacing in "SASL mechanism(s) not available" error message amends fdb03b91. 2019-02-20 18:19 Klemens Nanni * src/drv_imap.c: Fix CopyArrivalDate on platforms without glibc strptime(3)'s "%d" day of the month conversion specifier does not accept leading blanks in case of single digit numbers. "%e" does that. While implementation details and differences between the two day-of-month conversion specifiers vary, none of the major libcs (incl. OpenBSD, FreeBSD, Illumos, musl) consume a leading blank for "%d" except glibc, which consumes any number of spaces like in the "%e" case. Using "%e" ensures that date strings like " 4-Mar-2018 16:49:25 -0500" are successfully parsed by all major implementations in compliance to X/Open Portability Guide Issue 4, Version 2 ("XPG4.2"). musl is now the only one that still treats "%d" and "%e" without stripping any space. Issue analysed and reported by Evan Silberman who found mbsync 1.3.0 on OpenBSD 6.4 to fail with `CopyArrivalDate' set when syncing mails with the above mentioned timestamp. See https://marc.info/?l=openbsd-tech&m=155044284526535 for details. 2019-02-05 10:23 Gergely Risko * src/drv_imap.c: Work around useless SASL warnings Ater sasl_client_step() is called and the Cyrus SASL library forwards it to the client plugin, if the result value is OK (authentication succeeded), the clientout is filled out to be an empty string, even if the client plugin wanted to return NULL. To avoid that mbsync complains at this point, check the returned length instead of the pointer. 2019-01-04 23:00 Oswald Buddenhagen * src/drv_proxy_gen.pl: fix formatting of uint in callback debug stubs amends bb632d1c. 2018-11-24 13:15 Oswald Buddenhagen * src/: driver.c, driver.h, drv_imap.c: sort messages from UID FETCH request turns out that some IMAP servers (e.g., poczta.o2.pl) do not return messages in ascending UID order in response to a UID FETCH request, which makes the driver violate the API contract. counter this by sorting the messages. this also addresses the long-standing (but hypothetical) issue that parallel UID FETCH requests could be handled out-of-order and thus also lead to mixed up results. based on patch by Marcin Niestroj . 2018-09-09 11:35 Oswald Buddenhagen * src/drv_imap.c: bump IMAP command buffer size to 4KiB while only 1KiB is required by the IMAP spec, AUTHENTICATE GSSAPI with Kerberos requires about 1700 bytes. accomodate that, plus some reserve. fix suggested by Tollef Fog Heen via Debian BTS. 2018-09-08 16:36 Oswald Buddenhagen * src/socket.c: use SNI when connecting with SSL based on patch by Vincent Bernat . 2018-07-01 11:22 Oswald Buddenhagen * src/: drv_imap.c, socket.h: fix type of 'port' and check its range in config reader 2018-05-18 13:24 Klemens Nanni * src/: drv_maildir.c, drv_proxy.c: Fix time_t format strings For time_t, long long handles dates after Y2038 and should be safe on 32-bit architectures. From Jeremie Courreges-Anglas . 2018-05-18 13:11 Klemens Nanni * src/socket.c: User functions provided by recent LibreSSL versions At least on OpenBSD, this enables new APIs out of the box provided by LibreSSL 2.7.1 and higher. From Jeremie Courreges-Anglas . 2018-06-21 14:52 Michael J Gruber * src/: driver.h, drv_imap.c, drv_maildir.c, drv_proxy.c, sync.c: implement Forwarded flag maildir supports a 'P' flag which denotes the fact that a message has been 'passed' on (forwarded, bounced). notmuch syncs this to the 'passed' tag. Per https://tools.ietf.org/html/rfc5788, IMAP has a user-defined flag (keyword) '$Forwarded' that is supported by many servers and clients these days. (Technically, one should check for '$Forwarded' in the server response.) Restructure mbsync's flag parser to accept keywords (flags starting with '$') but still bail out on unknown system flags (flags starting with '\'). Support '$Forwarded' as a first keyword since it maps to maildir's 'P' and needs to be sorted in between the system flags. Signed-off-by: Michael J Gruber 2018-06-21 14:52 Michael J Gruber * src/: driver.h, drv_imap.c, drv_maildir.c, drv_proxy.c, sync.c: mark MAILBOX_DRIVER_FLAG locations in code Mailbox driver flags are defined in several places. It is essential that they are kept in sync, so mark them with the same string for easy grepping with an alerting boiler plate. Signed-off-by: Michael J Gruber 2018-07-01 09:05 Oswald Buddenhagen * src/drv_imap.c: fix IMAP UID sequence also in imap_find_new_msgs() use just * instead of the rather nonsensical *:* (which davmail happens to actually barf at). amends 72be55b0 (and 0a5a8479). 2018-04-08 16:10 Oswald Buddenhagen * src/drv_maildir.c: fix uidvalidity recovery with really long message-id headers re-using the file name buffer for the headers wasn't such a great idea, as _POSIX_PATH_MAX is only 256, while RFC2822 permits lines up to 1000 chars. and sure enough, i have a message with a whopping 470-char message-id header ... 2017-11-18 08:57 Oswald Buddenhagen * src/drv_imap.c: fix IMAP UID sequence in UIDNEXT determination fallback use just * instead of the rather nonsensical *:* (which davmail happens to actually barf at). amends 72be55b0. 2017-10-15 14:52 Oswald Buddenhagen * src/util.c: make more use of equals() 2017-10-15 14:14 Oswald Buddenhagen * src/: config.c, main.c, sync.c, util.c: make map_name() interpret empty strings as "no separator" empty strings were previously meaningless, and starting with 72c2d695a, failure to handle them lead to bogus results when the IMAP hierarchy separator is legitimately empty (when the server genuinely supports none and none is manually configured). non-null can be asserted more cleanly than null-or-non-empty, so change the api like that. incidentally, this also removes the need to work around gcc's bogus warning in -Os mode. problem found by "Casper Ti. Vector" 2017-10-15 14:46 Oswald Buddenhagen * src/drv_imap.c: remove pointless conditional in assignment of ctx->delimiter amends 72c2d695a. 2017-10-15 09:34 Oswald Buddenhagen * configure.ac: add check for perl and its version 2017-10-07 12:30 Oswald Buddenhagen * src/util.c: limit -Wmaybe-uninitialized suppression to gcc >= 4.3 apple gcc 4.2 complains about the use of the pragma inside a function. clang also complains, but because the pragma is entirely unknown to it. as neither compiler emits the bogus warning in the first place, there is no point in suppressing it anyway. 2017-10-07 12:09 Oswald Buddenhagen * src/socket.h: don't forward-declare SSL types any more our current project structure precludes the clash between some indirect include of ssl.h and our definition of 'S' (or 'M', i don't remember) that happened on some system, so there is no need to avoid including it any more. this avoids complaints from some more picky compilers, as re-defining typedefs (even to the same thing) is illegal before C11. 2017-10-07 12:46 Oswald Buddenhagen * .gitignore: git-ignore tar ball signatures 2017-10-07 12:17 Oswald Buddenhagen * configure.ac: bump version 2017-10-01 13:21 Oswald Buddenhagen * README, configure.ac, src/Makefile.am, src/compat/.gitignore, src/compat/Makefile.am, src/compat/config.c, src/compat/convert.c, src/compat/isync.1, src/compat/isync.h, src/compat/isyncrc.sample, src/compat/main.c, src/compat/util.c, src/mbsync.1: delete the compat wrapper it was deprecated in 1.2. until 1.4 gets released, enough time will have passed for sure. 2017-10-01 13:06 Oswald Buddenhagen * configure.ac: bump version 2017-10-01 12:59 Oswald Buddenhagen * Makefile.am: adjust dist-hook to syntax change in .gitignore don't try to delete files in / ... amends 46e792c3d. 2017-10-01 08:44 Oswald Buddenhagen * Makefile.am, mbsync-get-cert: rename get-cert => mbsync-get-cert to avoid undue namespace pollution. inspired by debian. 2017-04-09 08:40 Oswald Buddenhagen * src/sync.c: make sync records with stray TUID non-fatal while the situation indicates an internal error, it is harmless in itself. also, printing some more information may help identify the problem. 2017-08-11 07:20 Oswald Buddenhagen * src/: compat/config.c, compat/isync.h, compat/main.c, drv_imap.c, mbsync.1, socket.c, socket.h: prune SSL 2 support OpenSSL actually did that a while ago already, so this was dead code. 2017-10-01 08:40 Oswald Buddenhagen * src/drv_maildir.c: another fix for -Wimplicit-fallthrough (new on master) 2017-09-23 10:52 Oswald Buddenhagen * Makefile.am: update debian packaging 2017-09-23 10:32 Alessandro Ghedini * src/drv_imap.c: Fix spelling of error messages 2017-10-01 08:04 Oswald Buddenhagen * src/: common.h, compat/isync.h, compat/main.c, main.c, socket.c: fixes for -Wimplicit-fallthrough 2017-10-01 06:15 Oswald Buddenhagen * configure.ac: bump version 2017-08-19 11:22 Helmut Grohne * configure.ac: use autoconf's built-in pkg-config support for OpenSSL the hand-crafted suppport did not work with cross-builds. 2017-08-11 06:50 Oswald Buddenhagen * src/: compat/config.c, compat/isync.1, drv_imap.c, mbsync.1: enable TLS 1.1 and 1.2 by default there is no reason not to, and debian even disabled 1.0 globally, because it's (theoretically) too insecure in some contexts (BEAST attack). in the compat wrapper, the UseTLSv1 option has been re-interpreted as v1.x, to avoid adding new options. 2017-08-05 18:28 Oswald Buddenhagen * configure.ac: bump version 2017-08-05 18:24 Oswald Buddenhagen * src/mbsync.1: mention the need for renaming Maildir files upon move mu4e config line offered by Ben Maughan . 2017-07-30 16:37 Oswald Buddenhagen * src/socket.c: fix spurious decompression errors while that's just bad api, inflate() can return Z_BUF_ERROR during normal operation. contrary to the zpipe example and what the documentation implies, deflate() actually isn't that braindead. add respective comments. REFMAIL: CALA3aExMjtRL0tAmgUANpDTnn-_HJ0sYkOEXWzoO6DVaiNFUHQ@mail.gmail.com 2017-07-30 11:47 Oswald Buddenhagen * src/socket.c: improve zlib error reporting zlib is not exactly thorough about always populating z_stream->msg, so fall back to the error code if necessary. 2017-06-21 07:33 Patrick Steinhardt * src/socket.c: socket: use next addrinfo if opening socket fails The `socket_connect_one` function previously did an `exit(1)` when encountering any errors with opening the socket. This would break connecting to a host where multiple possible addrinfos are returned, where the leading addrinfos are in fact impossible to connect to. E.g. with a kernel configured without support for IPv6, the `getaddrinfo` call may still return a hint containing an IPv6 address alongside another hint with an IPv4 address. Creating the socket with the IPv6 address, which will cause an error, lead us to exiting early without even trying remaining hints. While one can argue that the user should have compiled without HAVE_IPV6 or used an appropriate DNS configuration, we can do better by simply skipping over the current addrinfo causing an error. To do so, we split out a new function `socket_connect_next`, which selects the next available address info and subsequently calls `socket_connect_one` again. When no hints remain, `sock_connect_one` will error out at that point. 2017-05-14 07:42 Oswald Buddenhagen * Makefile.am: fix 'make log' with non-default git config format.pretty suggested by Aaron Jensen . REFMAIL: CAHyO48z0DcoFPC8rCNAL38oxVQtZNKifVd-NEF3sp1EfR-GgxQ@mail.gmail.com 2017-05-14 07:37 Oswald Buddenhagen * src/drv_maildir.c: fix build without BDB amends 83ebe902. REFMAIL: CAHyO48z0DcoFPC8rCNAL38oxVQtZNKifVd-NEF3sp1EfR-GgxQ@mail.gmail.com 2017-03-21 19:05 Oswald Buddenhagen * src/: common.h, driver.h, drv_imap.c, drv_maildir.c, drv_proxy.c, sync.c, util.c: make UIDs unsigned complies with the IMAP spec, thus removing the (not really) arbitrary limitation to INT_MAX for UIDs. 2017-04-02 15:21 Oswald Buddenhagen * src/sync.c: delay assignment of TUID when propagating messages go back to assigning TUIDs only right before actually propagating them. this avoids spurious "TUID lost" warnings. 2017-03-11 12:20 Oswald Buddenhagen * src/: driver.h, drv_imap.c, run-tests.pl, sync.c: move away from magic UIDs in the sync state the only legitimate "deviant" UID is zero, meaning "no message". this can be futher qualified by additional flags in the sync record, rather than using magic values for the UID. in fact, the zero UID (so far meaning only "expunged") was already optionally qualifed with "expired". as a side effect, driver->store_msg() now returns 0 instead of -2 for unknown UIDs. this was a hack to avoid translating the value later on, but it made the api horrible, and now it's superflous in the first place. 2017-04-01 15:02 Oswald Buddenhagen * src/sync.c: split off ephemeral sync record state to a separate member this allows us to simplify logging of expiration, as we now can just log the entire persistent state instead of fiddling with bits. 2017-03-19 10:53 Oswald Buddenhagen * src/: common.h, main.c, run-tests.pl, sync.c: autotest: implement much more thorough resumption verification the test will now make a test run for every journaled step, both right before and right after the logging. 2017-03-29 11:43 Oswald Buddenhagen * src/run-tests.pl: autotest: pre-assign all UIDs of the test messages this ensures stable results when the boxes are used with different OPEN_FLAGS (which will happen in a subsequent commit), at the negligible cost of removing the implicit test of the maildir driver's ability to enumerate new messages. 2017-04-02 12:57 Oswald Buddenhagen * src/: .gitignore, Makefile.am, common.h, driver.h, drv_imap.c, drv_maildir.c, drv_proxy.c, drv_proxy_gen.pl, main.c, mbsync.1, sync.c: introduce driver call debugging do that by wrapping the actual stores into proxies. the proxy driver's code is auto-generated from function templates, some parameters, and the declarations of the driver functions themselves. attempts to do it with CPP macros turned out to be a nightmare. 2017-03-24 18:24 Oswald Buddenhagen * src/: driver.h, drv_imap.c, drv_maildir.c, sync.c: let driver_t::openbox_box() return the UID validity ... and make 'uidvalidity' private to the drivers. 2017-01-29 14:39 Oswald Buddenhagen * src/: driver.h, sync.c: use a #define for invalid UIDVALIDITY 2017-03-24 17:43 Oswald Buddenhagen * src/: driver.h, drv_imap.c, drv_maildir.c, sync.c: introduce get_uidnext() driver callback ... and make 'uidnext' private to the imap driver. 2017-03-26 16:44 Oswald Buddenhagen * src/: driver.h, drv_imap.c, drv_maildir.c, sync.c: let driver_t::find_new_msgs() return the list of messages consistently with driver_t::load_box(). 2017-03-24 17:09 Oswald Buddenhagen * src/: driver.h, drv_imap.c, drv_maildir.c, sync.c: let driver_t::load_box() return the list of messages ... and make 'msgs', 'count', and 'recent' private to the drivers. 2017-03-24 16:44 Oswald Buddenhagen * src/: driver.h, drv_imap.c, drv_maildir.c, main.c: let driver_t::list_store() return the list of boxes ... and make 'boxes' and 'listed' private to the drivers. 2017-03-24 16:00 Oswald Buddenhagen * src/drv_imap.c: factor out transform_refcounted_msg_response() the missing cross of transform_refcounted_box_response() and transform_msg_response(). 2017-03-24 15:56 Oswald Buddenhagen * src/drv_imap.c: make struct imap_cmd_refcounted_state "abstract" take the callback out of it, so it can be individualized. so far, this only increases code size ... 2017-03-24 14:29 Oswald Buddenhagen * src/main.c: don't mess with the driver's mailbox list from outside the api specifies that the list remains owned by the driver, so poking around in it is ugly and risky. 2017-03-24 13:18 Oswald Buddenhagen * src/: driver.h, drv_imap.c, drv_maildir.c, sync.c: make driver_t::prepare_load_box() return the final options ... and make 'opts' private to the drivers. 2017-03-24 13:06 Oswald Buddenhagen * src/: driver.h, drv_imap.c, drv_maildir.c, sync.c: introduce get_box_path() driver callback ... and make 'path' private to the maildir driver. 2017-03-21 18:27 Oswald Buddenhagen * src/: driver.h, drv_imap.c, drv_maildir.c, main.c, sync.c: make set_bad_callback() a proper driver_t entry ... and make the pointers private to the drivers. 2017-03-19 12:50 Oswald Buddenhagen * src/: driver.h, drv_imap.c, drv_maildir.c, drv_proxy.c, main.c, sync.c: provide a proper getter callback for driver capabilities that way driver_t contains only callbacks. 2017-03-19 12:46 Oswald Buddenhagen * src/: driver.h, drv_imap.c, drv_maildir.c, main.c, sync.c: prepend "get_" to getters in driver_t this makes it callbacks consistently start with a verb. 2017-04-02 12:04 Oswald Buddenhagen * src/: run-tests.pl, sync.c: rewrite tracking of highest expired UID so far, we tracked the slave side, and calculated the master side on the fly. that complicated things unnecessarily. 2017-03-10 16:40 Oswald Buddenhagen * src/sync.c: streamline syncing of old entries the order of the conditionals was purely historical (pre 4ec56f8cf, anno 2005) and hard to follow, as were the comments. 2017-01-29 14:00 Oswald Buddenhagen * src/sync.c: sort uid exception list in a smarter place do it closer to where it is populated. that way the debug output is sorted, and we don't sort the list if it's known to be empty. 2017-01-28 18:19 Oswald Buddenhagen * src/drv_imap.c: add fallbacks for determining UIDNEXT if the server sends no UIDNEXT, do an initial FETCH to query the UID of the last message. same if the server sends no APPENDUID. this allows us to remove the arbitrary limitation of the UID range to INT_MAX, at the cost of additional round-trips. 2017-03-21 17:46 Oswald Buddenhagen * src/: drv_imap.c, drv_maildir.c, main.c: fix repeated listing of same Store with different flags multiple Channels can call driver_t::list_store() with different LIST_* flags. assuming the flags are actually taken into consideration, using a single boolean 'listed' flag to track whether the Store still needs to be listed obviously wouldn't cut it - if INBOX does not live right under Path and the Channels used entirely disjoint Patterns (say, * and INBOX*), the second Channel in a single run (probably a Group) would fail to match anything. to fix this, make store_t::listed more granular. this also requires moving its handling back into the drivers (thus reverting c66afdc0), because the actually performed queries and their possible implicit results are driver-specific. note that this slightly pessimizes some cases - e.g., an IMAP Store with Path "" will now list the entire namespace even if there is only one Channel with Pattern "INBOX*" (because a hypothetical Pattern "*" would also include INBOX*, and the queries are kept disjoint to avoid the need for de-duplication). this isn't expected to be a problem, as listing mailboxes is generally cheap. 2017-03-21 14:12 Oswald Buddenhagen * src/drv_maildir.c: factor out listing Maildir++ Stores Maildir++ is sufficiently different from the other SubFolder styles to justify a separate function; the resulting code duplication is minimal, but the separated functions are a lot clearer. 2017-03-21 13:39 Oswald Buddenhagen * src/drv_maildir.c: fix exclusion of bogus "INBOX.*" folders in Maildir++ this also adds code which avoids that the message about excluding the mailbox is printed multiple times - this could happen with Maildir++, as the hierarchy is flattened. amends 0f24ca31b. 2017-03-19 19:21 Oswald Buddenhagen * src/drv_maildir.c: make "Patterns *" match INBOX* in Maildir++ Stores this also has the side effect that we won't fail to include INBOX itself when Inbox is nested under Path when using other SubFolder styles (regression introduced with Maildir++ support in 0f24ca31b). REFMAIL: 1489492069.2148187.910409864.7727F9FC@webmail.messagingengine.com 2017-03-19 17:08 Oswald Buddenhagen * src/main.c: make help screen print some more compile time options 2017-03-04 11:47 Oswald Buddenhagen * src/drv_imap.c: de-obfuscate cmd_sendable() split the monster conditional and add comments. 2017-03-30 17:39 Oswald Buddenhagen * src/: drv_imap.c, run-tests.pl: add comments 2017-03-30 18:04 Oswald Buddenhagen * src/sync.c: fix sync resumption with aborted entries we need a separate log entry type which does proper mmaxxuid tracking. while moving code around, this also removes a redundant debug statement. amends b1842617. 2017-03-30 17:57 Oswald Buddenhagen * src/sync.c: remove nonsensical statement from journal replay of aborted entries at this stage, entries cannot possibly have messages assigned to them, so trying to unlink them makes no sense. amends b1842617. 2017-03-30 17:48 Oswald Buddenhagen * src/sync.c: fix sync resumption with re-newed messages the UID of the entries needs to be bumped from -1 to -2, as otherwise the resumed run would see a TUID in a sync entry which may not have one. 2017-03-30 17:44 Oswald Buddenhagen * src/sync.c: don't emit redundant flag updates for re-newed messages 2017-03-19 10:35 Oswald Buddenhagen * src/sync.c: fix maxuid tracking newmaxuid represents the highest UID for which a sync entry was created, while maxuid represents the end of the range which is guaranteed to have been propagated. that means that the former needs to be instantly incremented (and logged), while the latter must not be touched until the entire new message sync completes. this matters particularly in the case of resuming an interrupted run, where sync entry creation must resume exactly where it left off, while loading the box must use the old limit to ensure that all messages are available for actual propagation. 2017-03-31 10:39 Oswald Buddenhagen * src/sync.c: de-duplicate journal replay somewhat we've been using indices to separate master/slave state for a long time, so there is no point in using pairs of matching brackets to signify the side in the journal. instead, use somewhat descriptive letters (S[een], F[ind], T[rashed]) and the index itself. 2017-04-02 13:42 Oswald Buddenhagen * src/: common.h, config.h, drv_imap.c, drv_maildir.c, socket.h, tst_timers.c: use typedefs for structs more makes the code more compact (and consistent, as typedefs were already used in some places). 2017-04-02 13:24 Oswald Buddenhagen * src/sync.c: factor out jFprintf() 2017-03-29 13:14 Oswald Buddenhagen * src/sync.c: fix signedness of 'nex' variables they are derived from srec->status, which is unsigned. for not understood reasons, the compiler complains only after extending status to a full unsigned int. on the way, localize the declarations. 2017-04-02 10:03 Oswald Buddenhagen * src/: drv_imap.c, drv_maildir.c: don't use strncpy() to copy TUIDs latest since 77acc268, the code prior to these statements ensures that the full length is available, so just use memcpy(). the code for comparing TUIDs uses memcmp() anyway. 2017-03-26 19:06 Oswald Buddenhagen * src/run-tests.pl: autotest: improve valgrind integration introduce recognition of $USE_VALGRIND to run all mbsync invocations through valgrind. this also removes the seemingly purposeless --log-fd=3 indirection. 2017-03-29 14:31 Oswald Buddenhagen * src/run-tests.pl: autotest: write logs to files they can get long, and having actual files also helps with diffing. 2017-03-29 14:24 Oswald Buddenhagen * src/run-tests.pl: autotest: factor out readfile() function 2017-03-14 13:52 Oswald Buddenhagen * src/run-tests.pl: autotest: de-duplicate error reporting paths 2017-03-14 13:44 Oswald Buddenhagen * src/run-tests.pl: autotest: print consistent information for journal replay failures 2017-03-14 13:20 Oswald Buddenhagen * src/run-tests.pl: autotest: don't print expected result if the mbsync run itself fails there isn't an actual result to compare with anyway. 2017-03-31 11:16 Oswald Buddenhagen * src/run-tests.pl: autotest: de-duplicate: use print*() in show*() this actually adds some (minimal) transformation overhead, but it makes the relationship clearer. 2017-03-14 14:01 Oswald Buddenhagen * src/run-tests.pl: autotest: determine path of mbsync prior to chdir() that allows tmp/ to be a symlink to a ramdisk. 2017-03-14 10:10 Oswald Buddenhagen * src/run-tests.pl: autotest: use warnings 2017-03-14 10:09 Oswald Buddenhagen * src/run-tests.pl: autotest: remove stray close() call from printstate() 2017-03-11 12:27 Oswald Buddenhagen * src/sync.c: don't populate sync record map with invalid UIDs this would obviously just bloat the hash with nonsense, slowing down the actual lookup later. 2017-02-15 10:45 Oswald Buddenhagen * src/run-tests.pl: fix mislabeling of test 2017-01-28 17:26 Oswald Buddenhagen * src/drv_imap.c: make -DN print also the sent data 2017-02-15 16:25 Oswald Buddenhagen * src/drv_imap.c: don't arbitrarily limit UIDs to a billion, part 2 imap_find_new_msgs() had the same fixed limit as imap_load_box(). amends 815822d8. 2016-12-18 19:50 Oswald Buddenhagen * README, src/driver.c, src/driver.h, src/drv_imap.c, src/drv_maildir.c, src/mbsync.1, src/sync.c: implement Message-Id based UIDVALIDITY recovery 2016-12-18 20:22 Oswald Buddenhagen * src/: driver.h, drv_imap.c, drv_maildir.c, sync.c: don't fetch message size unless necessary when syncing flags but not re-newing non-fetched messages, there is no need to query the message size for all messages, as the old ones are queried only for their flags. 2016-11-06 16:26 Oswald Buddenhagen * src/drv_maildir.c: some reshuffling in maildir_scan() for clarity 2016-12-18 20:24 Oswald Buddenhagen * src/drv_imap.c: make fetching of partial UID ranges more flexible instead of a single hard-coded branch, use a generic method to split ranges as needed. this is of course entirely over-engineered as of now, but subsequent commits will make good use of it. 2016-11-05 17:33 Oswald Buddenhagen * src/sync.c: factor out app_cr 2016-11-05 17:33 Oswald Buddenhagen * src/sync.c: factor out copy_msg_convert() 2016-11-05 17:32 Oswald Buddenhagen * src/sync.c: factor out copy_msg_bytes() 2016-12-29 13:34 Oswald Buddenhagen * src/: common.h, drv_imap.c: make more use of strnlen() includes adding the so far superfluous prototype for the replacemnt to common.h. 2016-12-29 14:08 Oswald Buddenhagen * src/util.c: make use of memchr() in strnlen() replacement after all turns out the comment advising against it was bogus - unlike for memcmp(), the standard does indeed prescribe that the memchr() implementation may not read past the first occurrence of the searched char. 2016-12-29 14:06 Oswald Buddenhagen * src/util.c: adjust return type of strnlen() replacement it doesn't really matter, but it's nicer to stay consistent with the official prototype. 2016-12-29 13:10 Oswald Buddenhagen * src/: driver.h, sync.c: standardize on 'int' for message sizes that's what the sources already assumed anyway. size_t is total overkill, as No Email Ever (TM) will exceed 2GiB. this also fixes a harmless format string warning in 32 bit builds. 2016-11-13 21:20 Oswald Buddenhagen * src/sync.c: print actually read TUID in debug message 2016-11-13 21:19 Oswald Buddenhagen * src/sync.c: null-terminate lines read from state file & journal makes the subsequent code less convoluted. 2016-11-06 16:23 Oswald Buddenhagen * src/common.h: mark string_list_t as packed otherwise we'll regularly over-allocate due to the struct's stride. 2016-12-18 20:52 Oswald Buddenhagen * src/: common.h, sync.c, util.c: make more use of shifted_bit() technically, this introduces a redundant AND, but the compiler is smart enough to prove that (((A & M) ^ B) & M) == ((A ^ B) & M). 2016-11-06 16:22 Oswald Buddenhagen * src/: drv_imap.c, drv_maildir.c: make more use of nfstrndup() 2016-11-12 13:15 Oswald Buddenhagen * src/mbsync.1: document some additional uses for PipelineDepth 2016-12-11 11:09 Oswald Buddenhagen * src/util.c: silence bogus [-Wmaybe-uninitialized] with -O0/-O1/-Os 2016-12-04 10:23 Oswald Buddenhagen * src/drv_imap.c: accept NAMESPACE responses without hierarchy delimiter RFC2342 states that the delimiter may be NIL, which some servers apparently actually make use of. REFMAIL: CAM0xXk_FQ83CPrd37iQCMKtc1B2P8=u-r5jX0n2WE5Y+3483nQ@mail.gmail.com 2016-12-04 10:14 Oswald Buddenhagen * src/drv_imap.c: validate NAMESPACE response earlier ... and don't silently fail later on. 2016-12-03 18:18 Oswald Buddenhagen * src/drv_imap.c: inform user if LOGIN was skipped because of missing SSL 'AuthMechs *' technically includes LOGIN, so it is a bit unintuitive when it's still not used. 2016-12-03 19:00 Oswald Buddenhagen * src/drv_imap.c: make * not match LOGIN even in non-SSL builds this is consistent with the plain text transmission warning below. 2016-12-03 19:58 Oswald Buddenhagen * src/drv_imap.c: be more helpful when no SASL mechanisms are available 2016-12-03 19:58 Oswald Buddenhagen * src/drv_imap.c: fix LOGIN in SASL builds if AuthMechs includes more than just LOGIN and the server announces any AUTH= mechanism, we try SASL. but that can still fail to find any suitable authentication mechanism, and we must not error out in that case if we are supposed to fall back to LOGIN. 2016-12-03 13:32 Oswald Buddenhagen * src/drv_imap.c: fix LOGIN in non-SASL builds specifically, if AuthMechs included more than just LOGIN (which would be the case for '*') and the server announced any AUTH= mechanism, we'd immediately error out upon seeing it, thus failing to actually try LOGIN. 2016-11-20 10:47 Oswald Buddenhagen * src/drv_imap.c: don't arbitrarily limit UIDs to a billion the number was chosen to make queries more comprehensible when the server sends no UIDNEXT, but it appears that such insanely large UIDs actually show up in the wild. so send 32-bit INT_MAX instead. note that this is again making an assumption: that no server uses unsigned ints for UIDs. but we can't sent UINT_MAX, as that would break with servers which use signed ints. also, *we* use signed ints (which is actually a clear violation of the spec). it would be possible to special-case the range [1,inf] to 1:*, thus entirely removing arbitrary limits. however, when the range doesn't start at 1, we may actually get a single message instead of none due to the imap uid range limits being unordered. this gets really nasty when we need to issue multiple queries, as we may list the same message twice. a reliable way around this would be issuing a separate query to find the actual value of UID '*', to make up for the server not sending UIDNEXT in the first place. this would obviously imply an additional round-trip per mailbox ... 2016-11-04 20:23 Oswald Buddenhagen * src/sync.c: wrap message trashing into simple transactions trashing many messages at once inevitably overtaxes m$ exchange, and the connection breaks. without any progress tracking, it would restart from scratch each time, which would lead to a) it never finishing and b) many copies of the messages in the trash. full transactions as we do for "proper" syncing would be over the top, as it's not *that* bad if some messages get duplicated in the trash. so we record only the messages for which trashing completed, thus allowing some overlap between the attempts. 2016-11-05 17:16 Oswald Buddenhagen * src/sync.c: use a temporary for sanity 2016-11-04 20:09 Oswald Buddenhagen * src/: common.h, drv_imap.c, drv_maildir.c, sync.c, util.c: pre-sort exception list passed to driver->load_box() ... and use that to optimize the maildir driver somewhat. 2016-11-04 20:48 Oswald Buddenhagen * configure.ac, src/common.h, src/driver.h, src/drv_imap.c, src/drv_maildir.c, src/sync.c, src/util.c: abstract growable arrays somewhat ... and sneak in a C99 requirement on the way. just because. 2016-11-04 15:21 Oswald Buddenhagen * src/: drv_maildir.c, mbsync.1: fix SubFolders style Maildir++ turns out i misread the spec in a subtle way: while all other folders are physically nested under INBOX, the IMAP view puts them at the same (root) level. to get them shown as subfolders of INBOX, they need to have _two_ leading dots. this also implies that the Maildir++ mode has no use for a Path, so reject attempts to specify one. 2016-07-24 09:58 Oswald Buddenhagen * src/socket.c: fix build with openssl 1.1 they finally made their structs opaque, and provided proper getters. 2016-07-24 09:58 Oswald Buddenhagen * src/socket.c: prune obsolete #include hmac.h was needed only for the cram-md5 implementation. 2016-05-21 11:08 Oswald Buddenhagen * src/socket.c: fix server certificate validation error reporting use the right function to decode the error code. found by Andrés Ramírez . 2015-11-08 11:19 Oswald Buddenhagen * .gitignore, src/.gitignore, src/compat/.gitignore: improve .gitignore files - add missing entries - remove redundant entries which are inherited from parent dirs - mark dirctories as such - anchor specific files 2015-11-06 07:29 Oswald Buddenhagen * src/: compat/isync.1, compat/isyncrc.sample, mbsyncrc.sample: fix CertificateFile docs & samples the mbsync manual says explicitly that the system's default certificate store should *not* be specified. however, the isync manual talked about CA certificates, which is (and always was) exactly wrong. also adjust both .sample rc files. 2015-09-27 10:13 Oswald Buddenhagen * src/socket.c: don't crash when dns lookup fails (ipv6 path) we call socket_connect_bail() when getaddrinfo() failed, so it must deal with no addrinfo being there yet. 2015-09-27 09:47 Oswald Buddenhagen * src/drv_maildir.c: remove legacy (bsd-style) locking flock() may be implemented via fcntl(), which may cause the process to deadlock itself when trying to apply both types of locks. this is the case even on linux when the file lives on NFS. it's unlikely that anything except mbsync would try to access the .uidvalidity files anyway, so there is no point in trying to be compatible with anything else ... REFMAIL: uddy4g589ym.fsf@eismej-u14.spgear.lab.emc.com 2015-09-06 20:56 Oswald Buddenhagen * src/drv_imap.c: don't attempt to issue LOGOUT on bad stores amends 9d22641b. 2015-09-06 19:02 Oswald Buddenhagen * src/socket.c: de-duplicate cleanup of name-related data in error paths "name" being both the ipv6 dns info and our own socket label. sort-of amends 9d22641b. 2015-09-07 10:23 Oswald Buddenhagen * README, src/mbsync.1: mention safety of concurrent access; wording improvements 2015-09-01 12:21 Oswald Buddenhagen * src/: common.h, drv_imap.c, sync.c, util.c: tolerate case changes in X-TUID header name it is legal for an email system to simply change the case of rfc2822 headers, and at least one imap server apparently does just that. this would lead to us not finding our own header, which is obviously not helpful. REFMAIL: CA+fD2U3hJEszmvwBsXEpTsaWgJ2Dh373mCESM3M0kg3ZwAYjaw@mail.gmail.com 2015-08-08 17:45 Anton Khirnov * src/: drv_imap.c, mbsync.1, socket.c, socket.h: add support for sending a TLS client certificate 2015-07-18 16:17 Oswald Buddenhagen * configure.ac: fix configure for static libdb, libnsl, and libsocket the right variable to put libraries into is LIBS, not LDFLAGS. REFMAIL: CAABPU68s3uy0Gv-vfAGzeNn0s5Ow--+p+y8W7xE7US_7iXpdjw@mail.gmail.com 2015-05-24 16:20 Oswald Buddenhagen * README: mention m$ exchange MOVE workaround in compat section 2015-05-24 16:20 Oswald Buddenhagen * README: list more deps (sasl and zlib) 2015-05-24 16:20 Oswald Buddenhagen * README: less technical info no point in listing IMAP extensions in the README 2015-05-23 09:06 Oswald Buddenhagen * src/: driver.h, drv_imap.c, drv_maildir.c, main.c: make it possible to specifiy Pattern INBOX* with no Path defined that pattern may very well expand to INBOXNOT, which would naturally live under Path, so we need to look into the Path. of course, this actually makes sense only if there *is* a Path, and complaining about it being absent is backwards. 2015-05-23 08:47 Oswald Buddenhagen * src/drv_imap.c: remove support for multi-char imap path delimiters again the idea that this is even possible was based on an incomplete reading of the imap spec. however, the infrastructure for supporting multi-char delimiters as such is retained, as the Flatten option can be used with them. 2015-05-24 09:37 Oswald Buddenhagen * src/: driver.h, drv_imap.c, drv_maildir.c, main.c, socket.c: make server connection a cancellable operation this entails splitting drv->open_store() into alloc_store() and connect_store(). 2015-05-17 14:28 Oswald Buddenhagen * src/drv_maildir.c: validate Path earlier we cannot know whether it will be needed later, but we can validate it if it's set. 2015-05-17 10:06 Oswald Buddenhagen * src/: main.c, sync.h: prune dead SYNC_FAIL_ALL define 2015-05-17 15:07 Oswald Buddenhagen * src/drv_imap.c: don't make bogus attempts at enabling compression recycling server connections skips everything up to setting up the prefix (Path/NAMESPACE). "everything" should obviously include enabling compression, as that must be done at most once per connection. 2015-05-09 16:00 Oswald Buddenhagen * configure.ac: bump version 2015-05-09 15:44 Oswald Buddenhagen * src/drv_imap.c: rename misnamed functions concerning sending imap commands cmd_submittable() => cmd_sendable() cancel_submitted_imap_cmds() => cancel_sent_imap_cmds() the sequence is exec -> submit -> send. 2015-05-09 17:18 Oswald Buddenhagen * src/: drv_imap.c, socket.c, socket.h: ensure direct exit after calling back any structures may be invalid after callback invocation. this has the side effect that the socket write callback now returns void, like all other callbacks do. 2015-05-09 17:17 Oswald Buddenhagen * src/: drv_imap.c, socket.c, socket.h: fix socket_write() recursion the synchronous writing to the socket would have typically invoked the write callback, which would flush further commands, thus recursing. we take the easy way out and make it fully asynchronous, i.e., no data is sent before (re-)entering the event loop. this also has the effect that socket_write() cannot fail any more, and any errors will be reported asynchronously. this is consistent with socket_read(), and produces cleaner code. this introduces a marginal performance regression: the maildir driver is synchronous, so all messages (which fit into memory) will be read before any data is sent. this is not considered relevant. 2015-05-09 15:12 Oswald Buddenhagen * src/drv_imap.c: fix #ifdefs around AuthMech & RequireCRAM these options don't depend on HAVE_LIBSSL. 2015-05-09 15:06 Oswald Buddenhagen * src/drv_imap.c: mask AUTHENTICATE PLAIN commands in error output as well amends bd0f3af5. 2015-05-02 16:59 Felix Janda * configure.ac: Add configure option for zlib 2015-05-08 08:20 Oswald Buddenhagen * src/: drv_imap.c, mbsync.1: add DisableExtension option to work around (server) bugs 2015-05-01 17:16 Oswald Buddenhagen * src/: drv_maildir.c, mbsync.1, mbsyncrc.sample, sync.c: support verbatim and real Maildir++ subfolder naming styles the legacy style is a poorly executed attempt at Maildir++, so introduce the latter for the sake of completeness. but most users will probably just want to use subfolders without any additional dots. 2015-05-01 15:29 Oswald Buddenhagen * src/drv_maildir.c: make maildir_list_recurse() recursion less convoluted move the unconditional addition of INBOX out ouf the function. this makes it possible to move the folder check and addition to the listing before the recursion, which seems clearer. 2015-05-01 11:19 Oswald Buddenhagen * src/drv_maildir.c: pass a maildir_store_conf_t to maildir_validate_path() casting early on makes the code clearer. 2015-05-01 18:19 Oswald Buddenhagen * src/main.c: make flags in pattern debugging non-cumulative 2015-05-01 16:39 Oswald Buddenhagen * src/mbsync.1: use \fB and \fI consistently, take 2 \fB means literal, while \fI means placeholder, value for placeholder, or emphasis. 2015-05-01 09:55 Oswald Buddenhagen * README, configure.ac: fix consistent misspelling of Berkeley 2015-05-01 09:48 Oswald Buddenhagen * README, configure.ac: the minimum required bdb version is in fact 4.1 this is the one that introduced the transaction argument to db->open(). 2015-05-01 09:45 Oswald Buddenhagen * configure.ac: make the bdb check actually check for a linkable library it only checked whether the header is compilable. amends e1d0ea8a1. 2015-04-26 18:54 Oswald Buddenhagen * src/: driver.h, drv_imap.c, drv_maildir.c, main.c: make skipping of failed stores more thorough in the case of imap stores, the failure is bound to the server config, not just the store config. that means that the storage of the failure state needs to be private to the driver, accessible only through a function. 2015-04-06 14:49 Oswald Buddenhagen * src/: drv_imap.c, mbsync.1, socket.c, socket.h: add socket timeout handling 2015-04-26 16:15 Oswald Buddenhagen * src/util.c: remove caching of current time it's too hard to reliably predict when invalidation will be necessary. 2015-04-26 16:34 Oswald Buddenhagen * src/util.c: don't get system time when dealing with null timers they fire immediately regardless of wall time, so we can save some pointless syscalls. 2015-04-26 10:07 Oswald Buddenhagen * src/main.c: fix -DN not implying -Dn 2015-04-18 09:46 Oswald Buddenhagen * src/drv_maildir.c: make it possible to nest maildir Path under Inbox simply make the code symmetrical to the inverse case. note that the result will be sort of awkward, as the folders under Path (and thus the subfolders of Inbox) don't start with a dot, while the subfolders of these folders do. this needs to be addressed separately. 2015-04-18 09:42 Oswald Buddenhagen * src/drv_maildir.c: make handling of Inbox-in-Path nesting less obfuscated when we run into Inbox while listing Path, check whether Inbox is being listed anyway, and just skip it if so, instead of listing it right away and resetting LIST_INBOX (and thus having a calling order dependency). 2015-04-18 08:54 Oswald Buddenhagen * src/drv_imap.c: don't list IMAP Path under INBOX twice if NAMESPACE is "INBOX.", listing INBOX recursively will already include it. REFMAIL: 1890363108.1020695.1428757117731.JavaMail.yahoo@mail.yahoo.com 2015-04-13 07:17 Oswald Buddenhagen * src/drv_maildir.c: fix uninitialized variable warning the returned UID is not used when trashing messages, but we still shouldn't just return an undefined value. 2015-04-11 18:06 Reimar Döffinger * README, configure.ac, src/Makefile.am, src/compat/Makefile.am, src/drv_maildir.c: Make Berkley DB an optional dependency. It doesn't seem necessary for any of the basic functionality. Signed-off-by: Reimar Döffinger 2015-04-09 08:05 Oswald Buddenhagen * src/drv_imap.c: fix SASL, take 2 USER (the authorization identity) specifies whom to act for. AUTHNAME (the authentication identity) specifies who is acting (and thus whose PASS is being used). USER is derived from AUTHNAME if omitted, but apparently the GSS-API module automatically adds the REALM, which is not helpful. it appears to be common to set both USER and AUTHNAME to the same value, so let's just do it as well. REFMAIL: 20150407194807.GA1714@leeloo.kyriasis.com 2015-04-03 20:38 Dmitrij D. Czarkoff * src/drv_maildir.c: fix crash in maildir_set_msg_flags() memcpy(3)'s behavior is undefined when source and destination addresses overlap, and it actually crashed on OpenBSD. use memmove() instead. 2015-04-03 12:03 Oswald Buddenhagen * Makefile.am: add cov-scan target 2015-04-03 11:24 Oswald Buddenhagen * configure.ac: bump version 2015-03-30 12:52 Oswald Buddenhagen * src/: drv_imap.c, mbsync.1: don't insert unnecessary linebreaks upon PassCmd invocation the PassCmd will be typically non-interactive (or it will use a gui password agent), so starting a new line just makes the progress counter uglier. so make it configurable and default to no line break. 2015-03-30 12:27 Oswald Buddenhagen * src/main.c: fix crash when no mailboxes match Patterns filter_boxes() just returns a null pointer in this case. REFMAIL: 20150330121211.GA10315@venus.fritz.box 2015-03-30 10:59 Oswald Buddenhagen * src/drv_imap.c: fix SASL PLAIN for User != $USER REFMAIL: 87d29mysnx.fsf@ericabrahamsen.net 2015-03-26 17:09 Oswald Buddenhagen * src/: common.h, main.c, mbsync.1: add debugging for main() so far, that's mostly mailbox listing 2015-03-23 07:42 Oswald Buddenhagen * src/: common.h, drv_imap.c, drv_maildir.c, main.c, mbsync.1, sync.c, util.c: revamp console output options - the old meaning of -V[V] was moved to -D{n|N}, as these are really debugging options. - don't print the info messages by default; this can be re-enabled with the -V switch, and is implied by most debug options (it was really kind of stupid that verbose/debug operation disabled these). - the sync algo/state debugging can be separately enabled with -Ds now. 2015-03-28 16:26 Oswald Buddenhagen * src/: common.h, drv_imap.c, main.c, mbsync.1, sync.c: make progress counters global which means they are now cumulative, and include channels and boxes. 2015-03-28 16:51 Oswald Buddenhagen * src/main.c: pre-calculate channel and box lists (as far as possible) ... instead of determining them on the fly, because - it enables early display of totals (to be used soon) - it enables re-use of the data (to be used at some point) - the code is less cryptic note that we leak the data created in main(), consistently with other configuration-related data. 2015-03-26 16:28 Oswald Buddenhagen * src/main.c: don't claim that INBOX is absent even if it was not listed IMAP defines that INBOX is always present. 2015-03-26 16:27 Oswald Buddenhagen * src/main.c: rework Pattern application instead of creating three lists of mailboxes (common, master, slave) and deriving the mailbox presence from the list being processed, create a single joined list which contains the presence information. additionally, the list is sorted alphabetically (with INBOX first), which is neater. 2015-03-26 16:16 Oswald Buddenhagen * src/: common.h, util.c: static my_strndup() => extern nfstrndup() 2015-03-26 13:28 Oswald Buddenhagen * src/drv_maildir.c: make sure that INBOX always exists makes the Maildir driver consistent with IMAP. 2015-03-23 19:16 Oswald Buddenhagen * src/drv_imap.c: don't refuse to strip Path just because it's INBOX/ no ambiguity can result from this, so there is no reason to treat sub-folders of INBOX differently from any other namespace. 2015-03-23 17:05 Oswald Buddenhagen * src/drv_imap.c: mask AUTHENTICATE PLAIN commands in debug output they are almost as bad as LOGIN. 2015-03-22 12:30 Oswald Buddenhagen * src/drv_imap.c: remove double "Logging in ..." when using legacy LOGIN 2015-03-23 18:00 Oswald Buddenhagen * src/main.c: fix out-of-Path INBOX never being matched by Patterns "(null)I" really doesn't cut it. amends cf0f32f8. 2015-03-22 10:44 Oswald Buddenhagen * src/mbsyncrc.sample: escape backslashes in PassCmd examples the config parser strips one level of backslash escapes. 2015-03-21 11:18 Oswald Buddenhagen * src/drv_imap.c: fix bogus "unexpected command continuation request" it helps if the code actually does what the comment above it claims. clarify it a bit, so i don't get stupid ideas again. This reverts commit cf6a7b4d182d2fe82f7371af9e5a857818f3d02d. 2015-03-07 16:46 Oswald Buddenhagen * src/drv_imap.c: fix chaining of COMPRESS invocation it was bound to the use of NAMESPACE, which made no sense at all. 2015-02-15 17:13 Oswald Buddenhagen * src/: common.h, config.c, driver.h, drv_imap.c, drv_maildir.c, main.c, mbsync.1, socket.c, socket.h, sync.c: soft-limit peak memory usage propagating many messages from a fast store (typically maildir or a local IMAP server) to a slow asynchronous store could cause gigabytes of data being buffered. avoid this by throttling fetches if the target context reports memory usage above a configurable limit. REFMAIL: 9737edb14457c71af4ed156c1be0ae59@mpcjanssen.nl 2015-02-15 11:48 Oswald Buddenhagen * src/config.c: complain about excess values supplied to options 2015-02-15 11:19 Oswald Buddenhagen * src/socket.c: handle clean SSL connection shutdowns some servers actually bother to close down the SSL connection before closing the socket. this fixes the spurious "unhandled SSL error 6" messages. REFMAIL: 20150120114805.GA17586@leeloo.kyriasis.com 2015-02-15 11:15 Oswald Buddenhagen * src/: drv_imap.c, socket.c, socket.h: refactor socket EOF handling handling EOF already at the socket level isn't a very good idea - it breaks the abstraction, and makes implementing sane semantics hard. 2015-02-14 13:03 Oswald Buddenhagen * src/socket.c: fix crash on shutdown of compressed connection the callback may destroy the socket, so it is very unwise to use it for buffering the return value. use a temporary instead. 2015-02-14 12:30 Oswald Buddenhagen * src/socket.c: handle clean shutdown of zlib stream the server can actually close the zlib stream before closing the socket, so we need to accept it. we don't do anything beyond that - the actual EOF will be signaled by the socket, and if the server (erroneously) sends more data, zlib will tell us about it. REFMAIL: 1423048708-975-1-git-send-email-alex.bennee@linaro.org 2015-02-15 10:39 Oswald Buddenhagen * src/socket.c: don't try to flush if there is nothing to flush zlib reports Z_BUF_ERROR when a flush is attempted without any activity since the previous flush (if any). while this is harmless as such, discerning the condition from genuine errors would be much harder than avoiding the pointless flush in the first place. REFMAIL: eb5681612f17be777bc8d138d31dd6d6@mpcjanssen.nl 2015-02-15 10:38 Oswald Buddenhagen * src/: common.h, drv_maildir.c: introduce and use pending_wakeup() so we don't need to peek into internal data structures. 2015-01-03 23:39 Oswald Buddenhagen * src/: driver.h, drv_imap.c, drv_maildir.c, main.c: deal sensibly with permanent errors don't retry dead Stores for every Channel. this also introduces a state for transient errors (specifically, connect failures), but this is currently unused. 2015-01-01 18:25 Oswald Buddenhagen * src/drv_maildir.c: unify .isyncuidmap.db handling with that of .uidvalidity that is, open the database on demand when locking and close it again when unlocking. 2015-01-01 18:18 Oswald Buddenhagen * src/drv_maildir.c: refactor maildir_set_uid() and maildir_store_uidval() the latter now handles both the db and the plaintext file, so the former can make use of it. 2015-01-01 17:00 Oswald Buddenhagen * src/drv_maildir.c: rename some *uid*() => *uidval*() to better reflect their function 2015-01-01 15:49 Oswald Buddenhagen * src/drv_maildir.c: lock .uidvalidity on demand a maildir re-scan doesn't need to lock it if it doesn't need to allocate any new uids. 2015-01-01 12:24 Oswald Buddenhagen * src/drv_maildir.c: delay unlocking of .uidvalidity it's wasteful to re-lock all the time. instead, unlock in the background after 1-2 seconds of inactivity. 2014-12-29 01:08 Oswald Buddenhagen * src/: config.c, driver.h, drv_imap.c, drv_maildir.c, main.c, mbsync.1, sync.c, sync.h: add support for propagating folder deletions 2015-01-17 14:27 Oswald Buddenhagen * src/drv_maildir.c: don't make intermediate directories proper maildirs "phantom" mailboxes waste time on syncing. furthermore, mutt's mailbox navigator provides no means to enter subfolders of maildirs. 2014-12-29 01:01 Oswald Buddenhagen * src/drv_maildir.c: deal sensibly with incomplete maildir directories a directory is no mailbox unless it contains a cur/ subdir. but if that one is present, create new/ and tmp/ if they are missing. this makes it possible to resume interrupted maildir creations. 2014-12-29 01:00 Oswald Buddenhagen * src/drv_maildir.c: factor out maildir_clear_tmp() 2014-12-30 14:16 Oswald Buddenhagen * src/: main.c, sync.c, sync.h: supplement open_box() with box existence information from list_store() there is no point in trying to open a non-existing box before trying to create it. 2014-12-29 00:42 Oswald Buddenhagen * src/: driver.h, drv_imap.c, drv_maildir.c, sync.c: split create_box() off from open_box() this allows us to do something else than creating missing boxes depending on circumstances. hypothetically, that is. 2015-01-03 22:16 Oswald Buddenhagen * src/sync.c: open the mailboxes after loading the sync state this allows us to react differently to a box'es absence depending on the state. hypothetically, so far. 2014-12-27 22:50 Oswald Buddenhagen * src/sync.c: lock sync state lazily don't try to lock it until we actually read or write it. the idea is to not fail with SyncState * if we tried to load the state before selecting a non-existing mailbox. this is ok, because if the mailbox is missing, we obviously have no sync state pertaining to it, either. as a side effect, this allows simplifying an error path. 2014-12-27 22:39 Oswald Buddenhagen * src/: driver.h, drv_imap.c, drv_maildir.c, main.c, sync.c: split off open_box() from select_box() aka prepare_paths() reloaded. we'll need it in a moment. 2014-12-27 22:13 Oswald Buddenhagen * src/sync.c: factor out {prepare,lock,save,load}_state() 2014-12-14 16:03 Oswald Buddenhagen * src/config.c: de-duplicate handling of box operation (create & expunge) options loops work just fine ... 2014-12-27 21:13 Oswald Buddenhagen * src/: driver.h, drv_imap.c, drv_maildir.c, main.c, sync.c: make some driver function names more descriptive 2014-12-14 11:36 Oswald Buddenhagen * src/: driver.h, drv_imap.c, drv_maildir.c, sync.c: rename driver::prepare_opts() => prepare_load() ... and move it to the right place in the structure and fix the doc to not claim that it is called before select(). 2014-12-13 17:29 Oswald Buddenhagen * src/drv_imap.c: disable use of LITERAL+ for payloads > 100k when LITERAL+ is used, the server has no chance for early rejection of messages. this means that the client can upload megabytes for nothing. so simply don't use LITERAL+ for big messages. of course this adds server roundtrips, but that's tough luck. the limit could be arguably higher than 100k (or even configurable). i set it to ~2 sec with my fairly average DSL line. 2014-12-13 17:01 Oswald Buddenhagen * src/: drv_imap.c, socket.c, socket.h: fix handling of unsolicited BYE responses they can come in at any time, after which we must expect the connection to be closed (and not complain about it). 2014-12-13 16:57 Oswald Buddenhagen * src/drv_imap.c: fix treatment of untagged NO and BAD responses they aren't possible greeting responses. however, they are warning resp. error reports from the server, so print them accordingly. 2014-12-13 11:09 Oswald Buddenhagen * configure.ac, src/Makefile.am, src/drv_imap.c, src/socket.c, src/socket.h: added support for IMAP DEFLATE initial patch by Jesse Weaver , but mostly rewritten by me. 2014-11-08 14:42 Oswald Buddenhagen * src/: socket.c, socket.h: make socket writing buffered the primary objective is reducing the number of small SSL packets (which are always padded), but fewer syscalls in the non-SSL case should be good as well. 2014-10-26 20:10 Oswald Buddenhagen * src/: drv_imap.c, socket.c, socket.h: vectorize socket_write() the objective is making the buffer code aware of the total size of a write in advance. this commit doesn't take advantage of that yet. 2014-11-30 18:51 Oswald Buddenhagen * src/: common.h, util.c: remove support for faking notifications with the existence of timers, this is now superfluous. 2014-11-30 18:44 Oswald Buddenhagen * src/: socket.c, socket.h: use null timer instead of faking a socket notification 2014-11-30 17:41 Oswald Buddenhagen * src/: Makefile.am, common.h, tst_timers.c, util.c: add timers to mainloop they are called "wakeups", though, as timer_t already exists in time.h. 2014-11-29 18:15 Oswald Buddenhagen * src/: common.h, socket.c, socket.h, util.c: change socket notifier design instead of keeping the structures in an opaque array (which was a shadow of the struct pollfd array if poll() was supported), make them directly addressable. this has the advantage that notifier-altering operations (mostly en-/disabling) don't need to look up the structure by file handle each time. on the downside, data locality in the main loop is worse. neither of these have any real effect on performance. note that the structures are not allocated separately, but embedded into the the parent structure (like sockets already were). 2014-12-07 11:51 Oswald Buddenhagen * src/socket.c: factor out socket_open_internal() 2014-12-07 12:19 Oswald Buddenhagen * src/: common.h, config.c, driver.h, drv_imap.c, drv_maildir.c, sync.c, sync.h, util.c: introduce uchar, ushort & uint typedefs 2015-01-11 13:18 Oswald Buddenhagen * Makefile.am: skip merges during ChangeLog generation 2015-01-11 13:29 Oswald Buddenhagen * src/: driver.h, drv_imap.c, drv_maildir.c, sync.c: fix UID assignment with some non-UIDPLUS servers the seznam.cz IMAP server seems very eager to send UIDNEXT responses despite not supporting UIDPLUS. this doesn't appear to be a particularly sensible combination, but it's valid nonetheless. however, that means that we need to save the UIDNEXT value before we start storing messages, lest imap_find_new_msgs() will simply overlook them. we do that outside the driver, in an already present field - this actually makes the main path more consistent with the journal recovery path. analysis by Tomas Tintera . REFMAIL: 20141220215032.GA10115@kyvadlo.trosos.seznam.cz 2015-01-02 11:38 Oswald Buddenhagen * src/sync.c: fix conditional for early failure in cancel_done() 2015-01-02 10:29 Oswald Buddenhagen * src/main.c: don't leave 2nd store in limbo if opening 1st store fails synchronously we can't leave the store FRESH, as otherwise the error handling code will assume it is still being opened and will return to the main loop. depending on the config this would cause an immediate termination or an indefinite wait. 2014-10-26 21:03 Oswald Buddenhagen * src/drv_imap.c: remove stray CRLF from AUTHENTICATE continuations this re-introduces 6741bc94 (just a bit differently), thus effectively reverting fbfcfea5. i suppose this extra CRLF is needed by a broken CRAM-MD5 implementation of some server, which is why it was there in the original implementation as well. however, it breaks more pedantic non-broken servers. if somebody complains, we'll need to add a much more sophisticated hack. 2014-10-26 19:17 Oswald Buddenhagen * src/socket.h: cleanup dead cram() prototype 2014-12-29 01:16 Oswald Buddenhagen * src/drv_imap.c: fix more memcmp() abuse amends 1217193fb and 4f383a807. 2014-11-08 12:50 Oswald Buddenhagen * src/: socket.c, socket.h: fix acceptance of trusted SSL certs we should make no assumptions about the layout of OpenSSL's certificate store, in particular when they are wrong. so copy the interesting part instead of "deep-linking" into it. this code is uglier than it should be, but OpenSSL's extensive use of macros to manage data types would force us to include the ssl headers into our headers otherwise, which would be even uglier. REFMAIL: <545442CC.9020400@nodivisions.com> 2014-10-25 15:30 Oswald Buddenhagen * README, src/common.h, src/config.c, src/drv_maildir.c, src/main.c, src/mbsync.1, src/sync.c: introduce FieldDelimiter and InfoDelimiter options ... for windows fs compatibility. the maildir-specific InfoDelimiter inherits the global FieldDelimiter (which affects SyncState), based on the assumption that if the sync state is on a windows FS, the mailboxes certainly will be as well, while the inverse is not necessarily true (when running on unix, anyway). REFMAIL: 2014-10-25 13:06 Oswald Buddenhagen * src/: driver.h, sync.c: move orig_name out of store_t it's state specific to the synchronizer. 2014-07-27 16:41 Oswald Buddenhagen * src/: drv_imap.c, socket.c: nuke home-grown CRAM-MD5 support it was obsoleted by SASL support. i deem the additional dependency acceptable when one wants the feature. 2014-07-27 16:41 Oswald Buddenhagen * README, configure.ac, src/Makefile.am, src/drv_imap.c, src/mbsync.1: add SASL support patch initially by Jack Stone , cleaned up by Jan Synacek , ... and then almost completely rewritten by me. ^^ 2014-07-27 17:29 Oswald Buddenhagen * src/drv_imap.c: factor out ensure_user() and ensure_password() 2014-07-12 19:02 Oswald Buddenhagen * src/: drv_imap.c, mbsync.1: rework authentication mechanism configuration RequireCRAM (another fairly stupid "use if available" option) is now deprecated. instead, the AuthMech option can be used to give a precise list of acceptable authentication mechanisms (which is currently "a bit" short). in particular, this allows *not* using CRAM-MD5 even if it's available. 2014-07-27 13:42 Oswald Buddenhagen * src/: drv_imap.c, mbsync.1, socket.c, socket.h: make it possible to disable usage of system cert store 2014-07-27 16:10 Oswald Buddenhagen * src/: mbsync.1, socket.c: require Host if SSL is used despite Tunnel 2014-07-27 13:12 Oswald Buddenhagen * src/: socket.c, socket.h: make SSL certificate verification less arcane instead of using a callback which messes with the certificate chain verification, simply let OpenSSL ignore errors during that phase and check the result only afterwards. 2014-07-12 18:35 Oswald Buddenhagen * src/: config.c, config.h, drv_imap.c, mbsync.1, socket.c, socket.h: re-design SSL/TLS configuration the combinations of the various options made quite a mess. additionally, 'RequireSSL no' is inherently insecure - "use SSL if available" is plain stupid. the old options are still accepted, but will elicit a warning. 2014-07-06 08:06 Oswald Buddenhagen * src/: drv_imap.c, socket.c, socket.h: move use_imaps out of server_conf_t it doesn't belong there - it's a property of imap_server_conf_t. the port setup is now done while reading the config. this makes socket.[hc] imap-agnostic. 2014-07-12 11:50 Oswald Buddenhagen * src/compat/: isync.1, main.c: deprecate the compat wrapper after a decade, it's about time to phase it out. 2014-07-05 14:37 Oswald Buddenhagen * configure.ac: bump version 2014-10-04 16:26 Oswald Buddenhagen * src/: driver.h, drv_imap.c, drv_maildir.c, sync.c: fix memory management of current mailbox name it was a stupid idea to store the pointer to a variable we need to dispose in a structure which has its own lifetime. 2014-10-04 15:07 Oswald Buddenhagen * configure.ac, src/common.h, src/compat/config.c, src/compat/isync.h, src/compat/util.c, src/drv_imap.c, src/drv_maildir.c, src/main.c, src/sync.c, src/util.c: stop abusing memcmp() memcmp() is unfortunately not guaranteed to read forward byte-by-byte, which means that the clever use as a strncmp() without the pointless strlen()s is not permitted, and can actually misbehave with SSE-optimized string functions. so implement proper equals() and starts_with() functions. as a bonus, the calls are less cryptic. 2014-10-04 11:12 Oswald Buddenhagen * src/: drv_imap.c, mbsync.1: permit IMAP Stores with explicitly empty Path this is useful if the server sends an unhelpful NAMESPACE like "INBOX." (which precludes clean use of Patterns with the real INBOX). 2014-10-04 13:43 Oswald Buddenhagen * src/drv_imap.c: don't attempt to filter LIST response if there is no Path we won't filter anything in that case anyway. 2014-10-04 10:16 Oswald Buddenhagen * src/: config.c, drv_imap.c, drv_maildir.c: permit Maildir Stores without a Path it is perfectly reasonable to have a Store which has only an Inbox. 2014-10-04 13:37 Oswald Buddenhagen * src/drv_imap.c: use resolved Path for initial filtering of LIST response otherwise we'd ignore NAMESPACE, and funny things could happen. 2014-10-04 15:30 Oswald Buddenhagen * src/drv_imap.c: consider unexpected structure of NAMESPACE fatal 2014-10-04 09:43 Oswald Buddenhagen * src/drv_maildir.c: ignore INBOX only in Path itself, not its subfolders a box foo/INBOX cannot be mistaken for the INBOX, so there is no point in filtering these out. 2014-07-12 12:07 Oswald Buddenhagen * src/mbsync.1: use \fB and \fI consistently notably, the docu for the Sync option had it mixed up in the description. 2014-07-05 21:11 Oswald Buddenhagen * src/drv_imap.c: complain about RequireSSL with no SSL versions enabled 2014-07-05 21:10 Oswald Buddenhagen * src/drv_imap.c: actually use STARTTLS if only TLSv1.1 or TLSv1.2 is enabled 2014-07-05 21:03 Oswald Buddenhagen * src/drv_imap.c: clarify error message about missing connection details 2014-07-05 21:02 Oswald Buddenhagen * src/drv_imap.c: make store/account error messages less redundant this will become more relevant when more are added. 2014-07-05 20:53 Oswald Buddenhagen * src/mbsync.1: clarify effect of Tunnel on Host and Port 2014-07-05 20:52 Oswald Buddenhagen * src/: drv_imap.c, mbsync.1: don't ignore RequireSSL for PREAUTHenticated connections such connections don't support STARTTLS. that is reasonable, as whatever makes the connection preauthenticated (typically a Tunnel used to launch imapd via a shell login) must already rely on the connection's security. consequently, we would not try to use STARTTLS with such connections. unfortunately, we'd also skip the RequireSSL check as a side effect. this means that a rogue server (via a MITM attack) could simply offer a preauthenticated connection to make us not use SSL, and thus bypass server authentication. as a result, we could send potentially sensitive data to the attacker: - with Patterns used, we would send a LIST command which reveals the remote Path setting. this isn't very useful to an attacker. also, IMAP Accounts usually rely on the server-provided NAMESPACE to start with. - with Create enabled for the remote Store, we would upload messages from newly appeared local folders. this isn't a very likely situation, unless the attacker manages to convince the victim to move/copy interesting mails to a new folder right before the attack. - with Expunge enabled for the local Store, previously synchronized folders would be wiped. however, this would require the attacker to know the correct UIDVALIDITY of each remote folder, which would require incredible luck or convincing the victim to disclose them. the first mismatch would likely tip off the victim. in practice, someone with the level of technical and social engineering skills required for this attack would very likely find more attractive attack vectors. therefore, i don't consider this a particularly serious issue. configurations with UseIMAPS enabled or using a secure Tunnel were not affected to start with. a side effect of this fix is that most users of Tunnel will now need to explicitly set RequireSSL to false. an alternative approach would be defaulting all SSL-related settings to off when Tunnel is used. this would be too invasive for a patch release, but i'll consider it for 1.2. see also CVE-2014-2567 for the Trojita MUA. 2014-07-05 20:54 Oswald Buddenhagen * .gitignore: ignore coverity state directory 2014-07-02 06:47 Oswald Buddenhagen * src/sync.c: initialize store_t::name the field is marked foreign (for the drivers), so a recycled store may contain an old pointer in it. that would make our error path crash. REFMAIL: CAF_KswU7aBS7unnK+rdZy1PG_8SZUAW=tcg75HixDLLE0w3Lhw@mail.gmail.com 2014-07-02 06:40 Oswald Buddenhagen * src/sync.c: actually print the faulty mailbox name, not some garbage REFMAIL: CAF_KswU7aBS7unnK+rdZy1PG_8SZUAW=tcg75HixDLLE0w3Lhw@mail.gmail.com 2014-06-28 12:27 Oswald Buddenhagen * configure.ac: bump version 2014-06-28 09:58 Oswald Buddenhagen * src/drv_maildir.c: detect inconsistent state of highest assigned UID the highest assigned UID must always be at least as high as the highest actually found UID, as otherwise we'd hand out duplicate UIDs at some point. also, getting into such a state in the first place indicates some potentially serious trouble, or at least external interference (e.g., moving/copying a message from another folder without giving it a pristine filename). REFMAIL: 20140626211831.GA11590@sie.protva.ru 2014-06-28 09:04 Oswald Buddenhagen * src/drv_imap.c: zero-terminate imap literals now that we properly support literals for strings, we must expect that the consumer code will use them as strings. amends fc77feacc. discovered by Armands Liepins REFMAIL: CAF_KswXoxdm7KXnWW4b_1odf=XsE4qRqRN4AsecwcPF1d+dSTA@mail.gmail.com 2014-04-13 15:07 Oswald Buddenhagen * src/mbsync.1: don't lie about the default of User unlike the isync wrapper, mbsync does not have a default for the IMAP user. the remote user seldomly matches the local one, so "forwarding" it is more confusing than helpful. CCMAIL: 744389@bugs.debian.org 2014-04-12 17:02 Oswald Buddenhagen * src/drv_maildir.c: don't forget to reset message counts when skipping scan amends b6949c64d2. CCMAIL: 744259@bugs.debian.org 2014-04-12 17:00 Oswald Buddenhagen * src/drv_maildir.c: remove apparently pointless resetting of recent message count past this point, it's not used for anything anyway. 2014-04-12 16:59 Oswald Buddenhagen * src/compat/convert.c: error-check renaming of uid mapping database for pedantry. found by coverity. 2014-04-12 16:34 Oswald Buddenhagen * src/compat/convert.c: error-check reading of old uidvalidity and maxuid files found by coverity. 2014-04-12 16:31 Oswald Buddenhagen * src/sync.c: error-check committing of sync state a failure here is rather unlikely, but let's be pedantic. a failure is not fatal (we'll just enter the journal replay path next time), so only print warnings. found by coverity. 2014-04-12 16:30 Oswald Buddenhagen * src/sync.c: better error messages for sync state and journal related errors we can make perfectly good use of errno here. 2014-04-12 16:28 Oswald Buddenhagen * src/sync.c: remove pointless/counterproductive "Disk full?" error message suffixes the affected functions will set errno to ENOSPC when necessary. 2014-04-12 14:56 Oswald Buddenhagen * src/compat/config.c: fix "inverse copy&pasto" in account labeling code the code was copied and the original adjusted ... but not quite completely. this means that clashing server names never really worked since - not that i would have expected this to be a particularly common configuration to start with. :D also added comments explaining why there are two implementations of the same thing. amends aea4be19e3 (anno 2006). found by coverity. 2014-04-12 14:06 Oswald Buddenhagen * src/config.c: assert !where implying !pseudo to help poor coverity. 2014-04-12 13:28 Oswald Buddenhagen * src/sync.c: don't crash in message expiration debug print we would try to print the uids from the non-existing srec of unpaired messages while preparing expiration. this would happen only if a) MaxMessages was configured and b) new messages appeared on the slave but we were not pushing, so it's a bit of a corner case. found by coverity. 2014-04-12 13:16 Oswald Buddenhagen * src/main.c: fix segfault on passing --{create,expunge}-{master,slave} stupid copy&pasto. found by coverity. 2014-04-12 13:02 Oswald Buddenhagen * src/drv_imap.c: don't crash on malformed response code this would happen in the absurd corner case that the response code is properly terminated with a closing bracket, but the atom itself is an unterminated double-quoted string. NOT found by coverity. 2014-04-12 12:58 Oswald Buddenhagen * src/drv_imap.c: don't crash on truncated LIST response found by coverity. 2014-04-12 11:08 Oswald Buddenhagen * src/compat/main.c: remove pointless pointer assignment 2014-04-12 11:03 Oswald Buddenhagen * src/: drv_maildir.c, mdconvert.c: fix hypothetical buffer overflows if something managed to make the maildir .uidvalidity files big enough (possible only by appending garbage or scrambling them alltogether), we would overflow the read buffer by one when appending the terminating null. this is not expected to have any real-world impact. found by coverity. 2014-04-12 10:46 Oswald Buddenhagen * src/: drv_maildir.c, mdconvert.c: close a bunch of fd leaks in error paths found by coverity. 2014-03-19 09:27 Oswald Buddenhagen * src/util.c: actually use prime numbers for all hash bucket sizes for some reason lost in history, the prime_deltas were actually wrong, leading to using composite numbers. the right sequence is available at http://oeis.org/A092131. 2014-03-19 09:09 Oswald Buddenhagen * src/config.c: fix zero MaxSize override in Channels REFMAIL: CA+Tk8fzb9i9LrC_k4G978c5XR5urNz_s0fpOn_-6EsdrBnEzSQ@mail.gmail.com 2014-03-10 10:57 Oswald Buddenhagen * src/compat/: config.c, isync.h, util.c: rework maildir store mapping the trivial approach of having "home" and "root" stores produced ugly results, and totally failed with the introduction of nested folder handling. instead, create a store per local directory, just as one would manually. CCMAIL: 737708@bugs.debian.org 2014-03-10 10:57 Oswald Buddenhagen * src/compat/config.c: don't needlessly quote strings 2014-03-10 10:54 Oswald Buddenhagen * src/compat/main.c: don't needlessly spell out INBOX 2014-03-09 15:38 Oswald Buddenhagen * src/compat/config.c: write Sync and Expunge to global section if applicable makes for leaner Channel sections. note: the global delete and expunge variables exist so the command line can override the config file despite the otherwise backwards behavior. 2014-03-09 14:56 Oswald Buddenhagen * src/compat/config.c: don't bother checking impossible condition the config readear already verified that at least host or tunnel are set. 2014-02-08 12:21 Oswald Buddenhagen * src/drv_imap.c: fix crash on store without prior fetch with non-UIDPLUS servers we'd never initialize the message list append pointer, so imap_find_new_msgs()'s FETCH would go awry. REFMAIL: <20140207101719.GB17125@mac.home> 2014-02-02 11:24 Oswald Buddenhagen * src/socket.c: remove pointless use of AI_V4MAPPED flag this flag is ineffective if ai_family is not explicitly AF_INET6. on top of that, attempting to use it breaks on FreeBSD. 2014-01-25 12:19 Oswald Buddenhagen * src/mbsync.1: fix typos 2014-01-25 10:34 Oswald Buddenhagen * src/drv_imap.c: don't error out if we don't get an X-TUID header the BODY[] item in the FETCH response corresponds to what we requested, and its presence doesn't imply that it actually contains anything useful - new messages may appear in the mailbox in addition to those we stored ourselves, and these will obviously have no TUID. 2014-01-02 19:50 Oswald Buddenhagen * configure.ac, src/common.h, src/drv_imap.c, src/util.c: make date parsing portable, take 2 the global timezone variable is glibc-specific. so use timegm() instead of mktime() for the conversion. as that is specific to the BSDs and glibc, provide a fallback. amends 62a6099. 2014-01-02 18:36 Oswald Buddenhagen * src/: drv_maildir.c, sync.c: fix _POSIX_SYNCHRONIZED_IO usage it can be -1 for unsupported, or 0 for runtime detection (which we don't do). 2014-01-02 20:08 Oswald Buddenhagen * configure.ac: bump version 2013-12-08 21:29 Oswald Buddenhagen * README, src/mbsyncrc.sample: pre-release doc updates 2013-12-14 11:37 Oswald Buddenhagen * src/mbsync.1: elaborate on expunging and trashing 2013-12-13 18:07 Oswald Buddenhagen * src/mbsync.1: clarify wording in MapInbox doc 2013-12-15 11:46 Oswald Buddenhagen * src/drv_imap.c: avoid array underflow in IMAP LIST .lock workaround suggested by Mark Wielaard . fwiw, the workaround really is still necessary with panda imap ... 2013-12-13 14:36 Oswald Buddenhagen * src/sync.c: MaxMessages: ignore entries with no master while calculating bulk fetch 2013-12-11 15:29 Oswald Buddenhagen * src/sync.c: adjust comments to new reality 2013-12-11 15:25 Oswald Buddenhagen * src/sync.c: ensure sequencing of message propagation and store closing by putting the message propagation last, d3f634702 uncovered a long-standing problem: we might have closed the source store before all messages were propagated from it. 2013-12-11 15:13 Oswald Buddenhagen * src/sync.c: fix error paths wrt sync drivers, take 3 msgs_copied() was not checked at all, and msgs_flags_set() was doing it wrong (sync_close() was not checked). instead of trying to fix/extend the msgs_flags_set() model (ref-counting and cancelation checking in lower-level functions, and return values to propagate the status), place the refs/derefs around higher-level scopes and do the checking only there. this is effectively simpler, and does away with some obscure macros. 2013-12-11 13:30 Oswald Buddenhagen * src/drv_imap.c: don't use UID EXPUNGE unless trashing a simple CLOSE is way more efficient, so use it if no adverse effects can come from it. 2013-12-08 19:46 Oswald Buddenhagen * .gitignore, configure.ac, src/Makefile.am, src/common.h, src/compat/isync.h, src/config.c, src/config.h, src/driver.c, src/driver.h, src/drv_imap.c, src/drv_maildir.c, src/main.c, src/mdconvert.c, src/socket.c, src/socket.h, src/sync.c, src/sync.h, src/util.c: reshuffle sources a bit split header and move some code to more logical places. 2013-12-08 15:37 Oswald Buddenhagen * src/: drv_imap.c, drv_maildir.c, isync.h, main.c: tag verbose output when channel links two verbose stores otherwise it's pure guesswork to assign the output to particular stores. 2013-12-08 15:32 Oswald Buddenhagen * src/: drv_imap.c, socket.c: move verbose socket logging out of socket driver the way it's used, it's more of a high-level function. 2013-12-08 14:49 Oswald Buddenhagen * src/: drv_imap.c, drv_maildir.c, isync.h, main.c: remove own_store() function from driver model the drivers which support it can abstract it inside open_store() just fine. 2013-12-08 14:11 Oswald Buddenhagen * src/drv_imap.c: make use of IMAP MOVE extension the Maildir driver is always exposing behavior equivalent to this - it's more efficient. 2013-12-08 09:48 Oswald Buddenhagen * src/drv_maildir.c: don't check for INBOX more than necessary 2013-12-08 09:44 Oswald Buddenhagen * src/drv_maildir.c: fix listing of nested maildir mailboxes 2013-12-08 08:49 Oswald Buddenhagen * src/: main.c, mbsync.1, mbsyncrc.sample: allow prefixes to Patterns this makes it possible to "rename" a "namespace" while syncing. 2013-12-08 08:51 Oswald Buddenhagen * src/main.c: less spaghetti 2013-12-07 16:24 Oswald Buddenhagen * src/main.c: factor out sync_listed_boxes() 2013-12-07 15:41 Oswald Buddenhagen * src/: main.c, mbsync.1: refuse box list overrides if Channel has no Patterns as the named boxes are the same on both sides, they logically make sense only when the channel is in that mode anyway, which is the case when using patterns. 2013-12-07 15:11 Oswald Buddenhagen * src/: isync.h, main.c, util.c: treat manually specified box list the same as one coming from Patterns 2013-12-01 16:57 Oswald Buddenhagen * src/socket.c: make host resolution error messages more useful in non-ipv6 builds 2013-12-01 16:45 Oswald Buddenhagen * src/drv_maildir.c: avoid useless delay after creating maildir box we would see the recent timestamp of the creation and conclude that something is going on, so we'd wait. this is obviously nonsense. as we know that a freshly created mailbox is empty, simply skip the message scan alltogether. 2013-11-02 20:42 Oswald Buddenhagen * src/: config.c, drv_maildir.c, isync.h, mbsync.1, run-tests.pl, sync.c: reduce FSync option to a boolean there is no use for Thorough mode any more, so simplify the configuration. 2013-11-02 20:41 Oswald Buddenhagen * src/sync.c: don't fsync after logging every TUID as we now don't actually start propagating new messages until all TUIDs have been generated, it's sufficient to sync just once. this makes it a cheap operation, so we can do it at SYNC_NORMAL level already. 2013-11-24 19:26 Oswald Buddenhagen * src/: config.c, isync.h, mbsync.1, run-tests.pl, sync.c: add ExpireUnread option 2013-11-24 18:39 Oswald Buddenhagen * src/: config.c, mbsync.1: make it possible to specify CopyArrivalDate and MaxMessages globally sneaky change on the side: the wording of the man page is changed from "outside any section" to "before any section" to get global options. this is not entirely true ... the previously existing options behave as before, while the two newcomers actually affect subsequent channels. 2013-11-24 18:32 Oswald Buddenhagen * src/: config.c, isync.h, main.c, sync.c: replace global_* with a channel_conf_t instance this makes the (growing) list of getopt_helper()'s parameters manageable. the few wasted bytes are worth it. 2013-11-24 18:55 Oswald Buddenhagen * src/: drv_imap.c, isync.h, main.c: do not unnecessarily use bitfields they don't save much (if any) space in our usage, while they make the machine code more bloated and slow. 2013-11-24 17:26 Oswald Buddenhagen * src/sync.c: move handling of new messages after that of old ones i.e., move it back. whatever the original reason was, it's now gone. this order is way more natural, which allows us to remove the osrecadd and S_DONE hacks. 2013-11-04 08:54 Oswald Buddenhagen * src/run-tests.pl: verify idempotence of all sync operations 2013-11-30 12:03 Oswald Buddenhagen * src/: run-tests.pl, sync.c: make MaxMessages work for new mails as well this helps enormously on the first sync of a 100k message box with a limit of 1k messages. it also happens to make the syncing idempotent. in a few conditionals we now explicitly test for max_messages being enabled, not smaxxuid != 0, as after the initial fetch with no important messages smaxxuid is zero, but we still have to skip over 99k messages in the above case. 2013-11-23 14:55 Oswald Buddenhagen * src/sync.c: delay propagation of new messages previous sequence: examine & propagate new => examine old => propagate old new sequence: examine new => examine old => propagate new => propagate old this alone does not buy us much ... 2013-11-02 18:33 Oswald Buddenhagen * src/sync.c: make message propagation recording less magic assign the sync record to the source message asap, and later on rely on a more explicit condition than not doing so. 2013-11-02 19:47 Oswald Buddenhagen * src/sync.c: log maxuid bumping less aggressively we can bump the internal variable whereever convenient, but we cannot log it until we know that all messages were copied, as otherwise we could miss some new messages after an interruption. with the new approach, interruption would merely cause some additonal traffic. 2013-11-17 16:36 Oswald Buddenhagen * src/sync.c: document message expiration transactions 2013-11-24 14:58 Oswald Buddenhagen * src/sync.c: propagate deletions with other flag changes less code duplication, more logical order of issued driver commands (especially after the next commit), and the "side effect" of letting the message expiration code see those deletions if they are asynchronous. 2013-11-17 10:23 Oswald Buddenhagen * src/sync.c: don't delay loading master even if messages were expired the delay optimized the corner case of previously important but now expired messages on the slave disappearing, either through an external expunge or after a journal replay. no point in pessimizing the common case. 2013-11-17 08:06 Oswald Buddenhagen * src/: run-tests.pl, sync.c: remove cleanup of expired entries during setup of master load the removed code would only ever trigger if a) we were after a journal replay or b) something external expunged the expired messages - both are corner cases not worth the extra code. however, this means that the syncing code further down now needs to take care of these zombies. in the end, the normal cleanup will take care of all expired entries, new and old. 2013-11-24 18:50 Oswald Buddenhagen * src/sync.c: micro-optimization/-clarification: swap condition order 2013-11-23 11:01 Oswald Buddenhagen * src/sync.c: make message counting in expiration code less confusing 2013-11-10 18:57 Oswald Buddenhagen * src/sync.c: count unread messages like flagged messages when expiring that is, don't count them towards the total only below the cut-off point. making them extend the working set even though they are inside it is counterintuitive. 2013-11-09 10:25 Oswald Buddenhagen * src/sync.c: use post-sync "seen" flag to determine expirability otherwise it wouldn't be idempotent. 2013-11-08 11:05 Oswald Buddenhagen * src/: compat/isync.1, sync.c: don't protect recent messages from MaxMessages while maildir has a clearly defined meaning of "recent" and for example mutt handles it graciously, IMAP's definition is fubared to the point that some servers (for example gmail) simply refuse to support it. for symmetry reasons it is best to pretend that it doesn't exist at all. it doesn't seem too useful anyway (the user can simply mark the messages as read to allow pruning). and last but not least, the man page of mbsync says nothing about "recent", only "unread". unlike the isync man page, though. 2013-11-23 11:22 Oswald Buddenhagen * src/sync.c: always get slave flags when we are expiring even if we are not propagating new messages, the appearance of new messages on the slave can lead to expiring older messages. for that, we need to know their importance, and thus flags. the alternative would be not doing an expiration run when not fetching new messages, but that would mean more conditionals all over the place. as the decision is somewhat arbitrary, just do the simpler thing. 2013-11-16 16:59 Oswald Buddenhagen * src/sync.c: do not trash expired messages we are not actually deleting them, so there is no point in saving them in the trash. 2013-11-16 12:25 Oswald Buddenhagen * src/: run-tests.pl, sync.c: make sync state header format less obscure the header is not space-critical, so use proper name-value pairs. this has the additional advantage that subsequent format changes can be done much easier. 2013-11-16 12:21 Oswald Buddenhagen * src/run-tests.pl: make state loading in showstate() similar to ckstate() 2013-11-09 12:06 Oswald Buddenhagen * src/run-tests.pl: take configs out of target state defs cleaner and less duplication 2013-11-16 12:41 Oswald Buddenhagen * src/run-tests.pl: more precise failure reporting 2013-11-03 19:17 Oswald Buddenhagen * src/run-tests.pl: make it possible to run only selected tests 2013-11-09 10:42 Oswald Buddenhagen * src/sync.c: set srec->msg[] when finding messages by tuid otherwise we would propagate phantom deletions. this affected only sync runs after an interruption while storing messages, so it went (mostly?) unnoticed. 2013-11-09 10:41 Oswald Buddenhagen * src/sync.c: remove pointless assignment we already know that tmsg->srec is null at this point. 2013-11-02 22:32 Oswald Buddenhagen * src/sync.c: assert no stray TUIDs 2013-11-30 14:07 Oswald Buddenhagen * src/drv_imap.c: initialize struct tm strptime() does not initialize at least tm_isdst, which leads to an uninited value reference in mktime(). 2013-11-09 13:35 Oswald Buddenhagen * src/: drv_imap.c, main.c: make use of strptime() portable it does not (officially) support the %z conversion, so re-implement that part by hand. 2013-11-09 12:53 Oswald Buddenhagen * src/drv_imap.c: fix compilation with older gcc versions the warning suppression pragma within function scope is apparently a new thing. as i don't want to disable the check for the entire function (even if this currently would make no difference), just use a wrapper function to suppress the format string check. 2013-11-09 12:50 Oswald Buddenhagen * configure.ac: fix strftime() %z conversion specifier check only glibc does something sane with gmtime()+strftime(). on bsd (incl. mac os), strftime() can be used only with localtime(). 2013-11-06 07:40 Oswald Buddenhagen * .gitignore: ignore automake's "compile" script 2013-11-06 07:37 Oswald Buddenhagen * autogen.sh: use autoreconf instead of calling separate tools this has been the correct way since a long time. Pointed-out-by: Felipe Contreras 2013-11-02 19:06 Oswald Buddenhagen * src/: isync.h, main.c, run-tests.pl, sync.c: add/fix comments and improve debug messages 2013-11-02 19:02 Oswald Buddenhagen * src/sync.c: simplify condition ... and document the cases. 2013-11-02 18:39 Oswald Buddenhagen * src/sync.c: micro-optimization/-clarification 2013-10-26 09:44 Oswald Buddenhagen * src/sync.c: move initializations for clarity 2013-05-20 16:54 Oswald Buddenhagen * src/sync.c: MaxMessages: make condition exactly symmetrical to condition below 2013-05-20 16:53 Oswald Buddenhagen * src/sync.c: rewrite condition for readability and consistency 2013-11-02 14:04 Oswald Buddenhagen * src/sync.c: remove assumption about value of M constant 2013-11-02 11:57 Oswald Buddenhagen * src/sync.c: fix enum abuse amends 9c86ec344. S_FIND was for the sync record status field. it has no business in the sync vars status fields. its value coincided with ST_SELECTED, which luckily only means that we always tried to match up TUIDs even if there was nothing to do. the need for TUID matching arises in two mostly independent circumstances, so add two separate flags ST_FIND_{OLD,NEW}. 2013-11-03 19:20 Oswald Buddenhagen * src/run-tests.pl: create unseen messages in /new/ seen messages still go to /cur/. this is consistent with the actual maildir driver. 2013-11-03 11:59 Oswald Buddenhagen * src/run-tests.pl: be a bit more verbose 2013-11-03 11:59 Oswald Buddenhagen * src/run-tests.pl: properly handle unexpected exit while replaying journal 2013-11-03 11:49 Oswald Buddenhagen * src/run-tests.pl: ensure that the journal replay pass really does nothing 2013-11-02 15:43 Oswald Buddenhagen * src/run-tests.pl: sort messages by serial number instead of UID in box dumper the input data is sorted that way, so it's easier to compare. 2013-11-02 14:42 Oswald Buddenhagen * src/run-tests.pl: fix error message in sync state dumper 2013-09-25 15:13 Oswald Buddenhagen * src/drv_imap.c: deal with messages disappearing between being listed and fetched 2013-09-25 18:56 Oswald Buddenhagen * src/: config.c, mbsync.1: support backslash-escaping in the config file note that no attempt is made at making this work in the compat wrapper. 2013-09-25 18:55 Oswald Buddenhagen * src/drv_imap.c: support backslashes and quotes in quoted IMAP strings the RFCs require it - well hidden in the BNF at the bottom. patch somewhat inspired by "guns" . 2013-09-25 16:53 Oswald Buddenhagen * src/drv_imap.c: make next_arg() more readable & efficient 2013-09-01 15:35 Oswald Buddenhagen * configure.ac, src/isync.h, src/socket.c: IPv6 support inspired by a patch by "Todd T. Fries" . 2013-09-01 14:32 Oswald Buddenhagen * src/: isync.h, socket.c: support multi-homed servers 2013-08-03 13:10 Oswald Buddenhagen * src/: config.c, drv_imap.c, isync.h, main.c, mbsync.1, sync.c, util.c: support multi-character path separators this applies to both the IMAP PathDelimiter (which is needed by Lotus Domino), as well as the Flatten-ed separators. 2013-07-27 16:46 Oswald Buddenhagen * src/drv_imap.c: CHECK before FETCH after STORE m$ exchange does not seem to update the index in time otherwise. 2013-07-28 13:55 Oswald Buddenhagen * configure.ac, src/config.c, src/drv_imap.c, src/drv_maildir.c, src/isync.h, src/mbsync.1, src/sync.c: added sync support for the arrival date of messages initial patch by Marc Hoersken 2013-07-27 18:17 Oswald Buddenhagen * src/sync.c: warn if we cannot find some messages by TUID 2013-07-27 16:44 Oswald Buddenhagen * src/: drv_maildir.c, sync.c: make better use of ATTR_UNUSED 2013-07-27 13:35 Oswald Buddenhagen * src/drv_imap.c: be somewhat stricter about the LIST response syntax the first token *must* be a list. 2013-07-27 13:32 Oswald Buddenhagen * src/drv_imap.c: allow the mailbox names in LIST responses to be literals Lotus Domino seems to send them like that. 2013-07-27 12:31 Oswald Buddenhagen * src/drv_imap.c: make parse_list() callback based this allows us to parse IMAP literals ({}) in every list. 2013-07-27 08:37 Oswald Buddenhagen * src/: drv_imap.c, mbsync.1, mbsyncrc.sample: add PassCmd option to query IMAP password dynamically inspired by patches by Aurélien Francillon , Martin Stenberg and sbfnk@users.sf.net. 2013-05-09 16:51 Oswald Buddenhagen * src/sync.c: don't unnecessarily use continue 2013-05-11 08:12 Oswald Buddenhagen * src/: config.c, sync.c: use INT_MAX instead of zero for "no size limit" this simplifies the actual conditions 2013-04-20 14:57 Oswald Buddenhagen * src/: drv_imap.c, drv_maildir.c, mbsync.1, socket.c, sync.c: update copyrights 2013-04-13 17:05 Oswald Buddenhagen * src/mbsync.1: man page fixups 2013-04-13 17:05 Oswald Buddenhagen * src/: main.c, mbsync.1: don't let wildcards match INBOX, unless it lives under Path it's counter-intuitive to have '*' match the (always present) INBOX when the rest of the mailboxes lives in a different namespace. 2013-04-13 17:25 Oswald Buddenhagen * src/drv_maildir.c: always list INBOX when asked for it it's there even if it's not there. says IMAP. no need to contradict. 2013-04-01 10:20 Oswald Buddenhagen * src/drv_maildir.c: split maildir_list_part() the boolean argument switched two entirely separate functions. 2013-04-01 10:30 Oswald Buddenhagen * src/drv_maildir.c: remove some temporaries in maildir_list_part() 2013-04-13 08:47 Oswald Buddenhagen * src/socket.c: fix CRAM-MD5 authentication the decoded challenge may be padded, so we really need to use strlen() rather than just the decoded length. 2013-04-13 08:50 Oswald Buddenhagen * src/socket.c: more consistency in char signedness 2013-04-07 15:20 Felipe Contreras * src/drv_maildir.c: maildir: fix trash path double-free It should be freed at the very end. Signed-off-by: Felipe Contreras 2013-04-07 14:53 Felipe Contreras * configure.ac: Fix build with recent autoconf and modernize configure.ac configure.ac:2: warning: macro 'AM_CONFIG_HEADERS' not found in library configure.ac:7: error: 'AM_PROG_CC_STDC': this macro is obsolete. You should simply use the 'AC_PROG_CC' macro instead. Also, your code should no longer depend upon 'am_cv_prog_cc_stdc', but upon 'ac_cv_prog_cc_stdc'. configure.ac:3: warning: AM_INIT_AUTOMAKE: two- and three-arguments Signed-off-by: Felipe Contreras 2013-04-07 10:42 Felipe Contreras * configure.ac: Rename configure.in to the modern equivalent Fixes: aclocal: warning: autoconf input should be named 'configure.ac', not 'configure.in' Signed-off-by: Felipe Contreras 2013-04-07 14:54 Oswald Buddenhagen * src/mbsync.1: discourage use of MapInbox 2013-03-30 09:10 Oswald Buddenhagen * src/drv_imap.c: don't try to fetch status of minus one message this would happen if we were trying to find newly pushed messages, but none actually arrived. as imap's ranges are not ordered, this would actually fetch one message. 2013-03-30 15:27 Oswald Buddenhagen * src/: run-tests.pl, sync.c: don't record newuid in the sync state this value is only ever used to find just pushed messages by TUID, so we can simply use the UIDNEXT value from before we started pushing - and of course, we need to record that in the journal. it makes no sense to log the new value after completing a search, as there won't be a next search before we push the next messages. 2013-03-30 08:38 Oswald Buddenhagen * src/sync.c: rename sync_vars_t::uidnext => newuid & fix comment the purpose of this variable is to hold the UIDNEXT value from before we started pushing new messages, i.e., the minimal uid we can expect them to have. 2013-03-30 13:14 Oswald Buddenhagen * src/: config.c, mbsync.1, util.c: make paths relative to CWD, after all the test suite actually relies on it. it would be possible to adjust it, but there is not much reason to make paths relative to HOME (as we support convenient tilde expansion). so use the least invasive approach, which is simply the old behavior. adjust the documentation accordingly. This reverts commit da5ce5d8f42a15a2842d6d14043452f1a7892a0a. 2013-03-29 17:22 Oswald Buddenhagen * src/socket.c: improve socket error reporting always use getsockopt() to query the meaning of POLLERR, rather than reporting "Unidentified socket error". this is unlikely to have any effect when using select(), as that one pretty much never signals exceptional conditions. 2013-03-29 16:51 Oswald Buddenhagen * src/socket.c: factor out socket_connect_failed() 2013-03-29 17:11 Oswald Buddenhagen * src/socket.c: improve socket connect() error reporting with poll() turns out that poll() may (and on linux does) signal POLLERR on connection failure. this is unlike select(), which is specified to signal write readiness in every case. consequently, check whether we are connecting before checking for POLLERR. 2013-03-29 15:00 Oswald Buddenhagen * src/: isync.h, main.c: introduce -DC option to only install a crash handler 2013-03-24 13:46 Oswald Buddenhagen * configure.in: don't claim that we are looking for exactly bdb 4.2 2013-03-24 12:09 Oswald Buddenhagen * src/mbsync.1: match flag names in man page "Full" is an alias for "All", but let's stick to one. 2013-03-24 10:10 Oswald Buddenhagen * src/: config.c, util.c: make path expansion match docu: paths are relative to ~ the current behavior of being relative to the current directory sort of makes no sense, and contradicts the docu. 2013-03-24 10:10 Oswald Buddenhagen * src/compat/: isync.1, main.c: disable SSLv2 by default in the wrapper as well 2013-03-23 14:07 Oswald Buddenhagen * src/drv_maildir.c: downcast time_t to long for printing time_t may be long long. to keep the sprintf format strings simple, just downcast - this is not going to be a problem for the next 30 years, and until then long will be 64-bit everywhere anyway. suggested 3.5 years ago by Antoine Reilles . 2013-03-23 08:59 Oswald Buddenhagen * src/drv_imap.c: fix cram-md5 authentication we need to send a newline after the response for imap to grok it. 2013-03-23 09:34 Oswald Buddenhagen * src/drv_imap.c: fix crashes in imap_open_store() error paths it's not a good idea to invoke imap_open_store_bail() twice, either ... 2013-03-17 13:32 Oswald Buddenhagen * src/socket.c: fix crash in ssl connection error path not a good idea to invoke the callback twice ... 2013-03-17 11:41 Oswald Buddenhagen * src/: isync.h, mbsync.1, socket.c: rewrite SSL certificate verification. again. leave all the hard work to OpenSSL. this has several consequences: - certificate chain validation actually works instead of throwing around error 20 - the interactive approval is gone. i don't expect it to be useful anyway, as mbsync is mostly a batch tool - the code is much shorter 2013-02-21 07:02 Oswald Buddenhagen * README: language fix 2013-02-21 07:01 Oswald Buddenhagen * README: make build instructions more explicit 2013-02-03 16:34 Oswald Buddenhagen * src/socket.c: fix CVE-2013-0289: add SSL subject verification we did not check a valid certificate's subject at all so far. this is no problem if the certificate file contains only exactly the wanted host's certificate - before revision 04fdf7d1 (dec 2000, < v0.4), this was even enforced (more or less - if the peer cert had been signed directly by a root cert, it would be accepted as well). however, when the file contains root certificates (like the system-wide certificate file typically does), any host with a valid certificate could pretend to be the wanted host. 2013-02-03 16:47 Oswald Buddenhagen * src/: drv_imap.c, isync.h, mbsync.1, socket.c: add support for (disabling) TLS v1.1 and v1.2 2012-10-16 07:27 Oswald Buddenhagen * src/drv_imap.c: more error checking of IMAP responses REFMAIL: CA+Tk8fyu-6bwXq=ee2BgcKK_13m9S0RS+-0DhM=_jFqSKCH8aw@mail.gmail.com 2012-09-22 15:48 Oswald Buddenhagen * src/: drv_imap.c, socket.c, util.c: flush stdout more to make sure it is timely written and not interleaved with stderr even when when redirected. 2012-09-22 15:35 Oswald Buddenhagen * src/sync.c: fix TrashRemoteNew copy direction 2012-09-16 11:03 Oswald Buddenhagen * src/main.c: consider hierarchy delimiter flattening when deciding what to list flattened sub-folders of INBOX actually end up in Path, so list that instead. REFMAIL: 6c0ecbff0d025387020281c5d2f5e6e8@smallsys.org 2012-09-16 10:34 Oswald Buddenhagen * src/main.c: try harder to list all necessary boxes the pattern "INB*" may or may not refer to something in the INBOX. even just "*" may. so list both the INBOX and the Path in case of uncertainty. 2012-09-15 13:15 Oswald Buddenhagen * src/: config.c, drv_maildir.c, isync.h, mbsync.1, run-tests.pl, sync.c: add option to control amount of fsync()ing 2012-09-15 12:38 Oswald Buddenhagen * src/sync.c: avoid that a system crash can cause messages to be propagated twice fdatasync() the journal after creating the pair record and recording the TUID, but before the message propagation actually starts. all other writes to the journal are not flushed, as they will at worst cause some unnecessary network traffic without visible effect. 2012-09-15 12:15 Oswald Buddenhagen * src/drv_maildir.c: avoid that a system crash can lose mails this fixes two possible failure scenarios: - if the journal is committed but the mails are not, the missing files would be erroneously interpreted as deletions which would be propagated - less seriously, if the mail files' meta data was committed but the file contents were not, we would end up with empty files, which would have to be re-fetched "behind mbsync's back" (just deleting the files would not work - see above) 2012-09-15 11:25 Oswald Buddenhagen * src/sync.c: avoid that a system crash can clobber the sync state file make sure that the new state is committed to disk before overwriting the old version - by default meta data is committed first, so we may end up with no valid state at all otherwise. 2012-09-15 09:57 Oswald Buddenhagen * src/compat/config.c: quote mailbox names written to config file 2012-09-15 09:49 Oswald Buddenhagen * src/config.c: make more config file errors fatal we really shouldn't just synchronize despite config parsing errors. 2012-09-15 09:46 Oswald Buddenhagen * src/: config.c, drv_imap.c, drv_maildir.c, isync.h: store config error status in conffile_t object this makes passing it around more straight-forward 2012-09-15 09:24 Oswald Buddenhagen * src/: config.c, drv_imap.c, isync.h, util.c: make config parser a bit more careful about quotes the parsing is more shell-like now: - quoted and unquoted parts can be mixed in one argument - the hashmark can be meaningfully quoted 2012-09-09 10:18 Oswald Buddenhagen * src/drv_maildir.c: call fdatasync() after updating .uidvalidity files they must be flushed before the file system meta data, as otherwise we may end up with duplicate UIDs after a system crash. 2012-09-02 15:35 Ben Kibbey * src/socket.c: Fix certificate verification. The connection state wasn't getting updated. 2012-08-26 13:17 Oswald Buddenhagen * README, src/compat/isync.1, src/mbsync.1: pre-release doc updates 2011-04-10 17:25 Oswald Buddenhagen * src/: compat/main.c, config.c, drv_imap.c, drv_maildir.c, isync.h, main.c, sync.c, util.c: update copyrights make the wrapper's help string also mention copyrights pertaining only to the actual syncer, as this is the only string many people will ever see. 2011-04-10 17:34 Oswald Buddenhagen * src/: compat/config.c, compat/convert.c, compat/isync.1, compat/isync.h, compat/main.c, compat/util.c, config.c, drv_imap.c, drv_maildir.c, isync.h, main.c, mbsync.1, mdconvert.1, mdconvert.c, run-tests.pl, socket.c, sync.c, util.c: replace FSF address with something more ... contemporary 2012-08-26 14:29 Oswald Buddenhagen * src/: Makefile.am, compat/Makefile.am: install the config examples to docdir 2012-08-26 14:16 Oswald Buddenhagen * Makefile.am: update debian packaging 2012-08-26 13:02 Oswald Buddenhagen * Makefile.am, isync.spec.in: fix rpm packaging 2012-08-26 11:36 Oswald Buddenhagen * src/: isync.h, sync.c, util.c: use a hash table for message => sync record lookup this removes the pathological O( * ) case at the cost of being a bit more cpu-intensive (but O()) for old messages. 2012-08-25 18:30 Oswald Buddenhagen * src/: drv_imap.c, mbsync.1: make use of UID EXPUNGE 2012-08-18 11:58 Oswald Buddenhagen * src/: config.c, isync.h, main.c, mbsync.1, sync.c: introduce ability to flatten the hierarchy of Stores 2012-08-11 16:34 Oswald Buddenhagen * configure.in, src/drv_imap.c, src/drv_maildir.c, src/isync.h, src/main.c, src/mbsync.1, src/util.c: add support for hierarchical mailboxes 2012-08-11 15:11 Oswald Buddenhagen * src/drv_maildir.c: calculate trash box path already in maildir_open_store() this gives us some cleaner code paths later on, as we can treat the trash box like a regular mailbox. 2012-08-11 15:05 Oswald Buddenhagen * src/drv_maildir.c: ensure that mailbox creation in maildir_store() is limited to trashing other mailboxes would have been maildir_select()ed already. 2011-06-13 10:13 Oswald Buddenhagen * src/drv_imap.c: refactor: imap_select2_p2 => imap_refcounted_done_box soon, we'll use it for something different, too 2012-08-25 13:34 Oswald Buddenhagen * src/sync.c: don't crash when select() on master fails synchronously svars->drv[S] would not be initialized yet, so cancel_sync() would crash. 2012-08-18 10:48 Oswald Buddenhagen * src/: isync.h, main.c, sync.c: fix error handling of invalid SyncState * when we find that the store is incompatible with in-store sync state, we want to fail the whole channel. however, we must not claim that the store died, otherwise it won't be disposed of properly. 2011-06-02 17:21 Oswald Buddenhagen * src/: drv_imap.c, drv_maildir.c: reject qualified mailboxes with the magic name INBOX otherwise we couldn't tell them apart from the real INBOX after stripping away the Path. 2011-07-25 07:25 Oswald Buddenhagen * src/: drv_maildir.c, mdconvert.c: suppress bdb complaints about unknown file format pass DB_TRUNCATE when creating databases. otherwise bdb will complain about the empty file we pass it (we have to create it upfront to implement our locking). 2011-06-02 10:43 Oswald Buddenhagen * src/: drv_imap.c, mbsync.1: Revert "fix UIDNEXT handling" in fact, UIDNEXT (and UIDVALIDITY) null is *not* allowed (see RFC3501 section 9). them popping up nonetheless was a dovecot bug (which would also confuse dovecot itself). having it in as a workaround was no good either, as quite some other code in mbsync assumes that UIDs are not null. This reverts commit e1fa867 and most of 39006d7. -REFMAIL: 4CA62BA1.4020104@lemma.co.uk 2012-08-25 13:29 Oswald Buddenhagen * src/: drv_maildir.c, isync.h, main.c, run-tests.pl: deal with concurrent maildir modifications during listing files may be renamed (due to new -> cur transition or flag changes), which may lead to two effects if ignored: - we see both the old and the new name, so we report a spurious duplicate UID - we see neither name, so we report a spurious deletion as countermeasure, record and compare directory modification times. upon mismatch, we just start over - as usual. 2011-05-03 07:42 Oswald Buddenhagen * src/drv_maildir.c: make maildir uidvalidity change fatal it's best to give the user a chance to fix it rather than completely messing up the syncstate by re-enumerating the UIDs. 2011-05-22 15:53 Oswald Buddenhagen * src/drv_maildir.c: cleanup maildir error paths don't try to unlock and close databases and files - this will happen a moment later anyway, through cancelation or re-selection. ironically, this plugs a memory leak, because an open main database is used as a signal to close a temporary db in maildir_scan(). 2011-05-22 15:23 Oswald Buddenhagen * src/drv_maildir.c: fix potential double free the store may be discarded before we reach maildir_select() again, which will leave us with a dangling pointer. 2011-05-22 15:22 Oswald Buddenhagen * src/drv_maildir.c: plug memory leak in maildir_store_msg() upon failure to acquire UID 2011-04-10 11:06 Oswald Buddenhagen * src/: drv_imap.c, drv_maildir.c, isync.h, run-tests.pl, sync.c: employ alternative scheme to finding messages by TUID instead of SEARCHing every single message (which is slow and happens to be unreliabe with M$ Exchange 2010), just FETCH the new messages from the mailbox - the ones we just appended will be amongst them. 2011-04-03 09:29 Oswald Buddenhagen * src/sync.c: clearer debug msg 2011-04-11 08:46 Oswald Buddenhagen * src/: isync.h, mdconvert.c: use ATTR_PRINTFALIKE 2012-09-01 15:21 Oswald Buddenhagen * src/: socket.c, sync.c, util.c: fix line wrapping before info messages unless an info message is explictly marked as a continuation, it must terminate any pending line (typically the progress information) first. debug output is not affected, as it is mutually exclusive with info output, and no debug lines are left unterminated outside clear scopes. 2011-06-02 08:14 Oswald Buddenhagen * src/: isync.h, main.c, util.c: remove Ontty flag i can't figure out why i added it in the first place. it doesn't seem to make any sense ... 2011-04-11 08:45 Oswald Buddenhagen * src/: isync.h, sync.c, util.c: centralize flushing of unfinished debug lines 2011-04-10 13:32 Oswald Buddenhagen * src/: compat/config.c, compat/convert.c, compat/isync.h, compat/main.c, compat/util.c, config.c, drv_imap.c, drv_maildir.c, isync.h, mdconvert.c, socket.c, sync.c, util.c: unify error reporting - introduce sys_error() and use it instead of perror() and error(strerror()) in all expected error conditions - perror() is used only for "something's really wrong with the system" kind of errors - file names, etc. are quoted if they are not validated yet, so e.g. an empty string becomes immediately obvious - improve and unify language - add missing newlines 2011-03-27 18:39 Oswald Buddenhagen * src/drv_maildir.c: don't complain about disappearing temp files some other process might be cleaning up concurrently ... 2011-03-27 15:50 Oswald Buddenhagen * src/isync.h: enlarge receive buffer considerably the tiny buffer makes no sense in the face of huge payloads and now additionally masses of replies from pipelined commands. 2011-03-13 14:03 Oswald Buddenhagen * configure.in, src/drv_imap.c, src/mdconvert.c: compile with -ansi -pedantic on gcc greatly helps portability ... 2012-09-01 19:14 Oswald Buddenhagen * configure.in, src/compat/isync.h, src/compat/main.c, src/isync.h: define _GNU_SOURCE on the command line that way it is already set in configure and can thus be used by tests. 2011-03-20 17:23 Oswald Buddenhagen * src/drv_imap.c: centralize imap_cmd_refcounted_state refcount decrementing no else branches remain, so the if() can be put into imap_refcounted_done() 2011-03-12 15:16 Oswald Buddenhagen * src/drv_imap.c: get rid of redundant literal_pending state flag 2012-08-25 16:26 Oswald Buddenhagen * configure.in, src/drv_imap.c, src/isync.h, src/mbsync.1, src/socket.c: fully asynchronous IMAP operation - asynchronous sockets using an event loop - connect & starttls have completion callback parameters - callbacks for notification about filled input buffer and emptied output buffer - unsent imap command queue - used when - socket output buffer is non-empty - number of commands in flight exceeds limit - last sent command requires round-trip - command has a dependency on completion of previous command - trashnc is tri-state so only a single "scout" trash APPEND/COPY is sent at first. a possibly resulting CREATE is injected in front of the remaining trash commands, so they can succeed (or be cancel()d if it fails). - queue's presence necessitates imap_cancel implementation 2011-03-13 13:29 Oswald Buddenhagen * configure.in, src/isync.h, src/main.c, src/util.c: add simple mainloop implementation not used so far 2011-03-19 18:40 Oswald Buddenhagen * src/socket.c: move responsibility for closing sockets on error to user the only user being imap and the first thing in imap_cancel_store() being a call to socket_close(), this code was pretty pointless anyway. 2011-03-27 14:50 Oswald Buddenhagen * src/: drv_imap.c, isync.h, socket.c: make socket read/write error reporting callback-based the functions still have synchronous return codes as well - this enables early error returns without having to resort to refcounting. 2011-04-03 16:47 Oswald Buddenhagen * src/: drv_imap.c, isync.h, socket.c: decouple the filling of the read buffer from consuming it this prepares the code for being called from a callback. notably, this makes the imap list parser have a "soft stack", so the recursion can be suspended at any time. 2011-03-27 10:34 Oswald Buddenhagen * src/drv_imap.c: centralize imap_cmd disposal 2011-03-13 13:12 Oswald Buddenhagen * src/: drv_imap.c, isync.h, socket.c: make socket_write() capable of taking ownership of the buffer that way the user code doesn't have to free it any more. 2011-03-13 12:40 Oswald Buddenhagen * src/: drv_imap.c, socket.c: change socket_write() return code semantics instead of returning a write()-like result, return only a binary status code - write errors are handled internally anyway, so user code doesn't have to check the write length. 2011-03-27 14:58 Oswald Buddenhagen * src/: drv_imap.c, mbsync.1: make IMAP pipeline depth configurable currently, this affects only "clustered" message listings and flag stores. 2011-03-19 21:12 Oswald Buddenhagen * src/drv_imap.c: cancel submitted commands when canceling store we already have some minimal asynchronicity, so there might be commands in flight when a fatal error comes in. 2011-01-23 13:06 Oswald Buddenhagen * src/: drv_imap.c, isync.h, socket.c: Socket_t + buffer_t => conn_t remove the layering, in favor of a "buffered connection" abstraction. 2011-04-10 11:28 Oswald Buddenhagen * src/socket.c: security fix: failure to load the certificate file is *not* OK ... 2011-01-23 12:43 Oswald Buddenhagen * src/: Makefile.am, drv_imap.c, isync.h, socket.c: move socket code to a separate file this makes the layering more obvious 2011-03-13 11:06 Oswald Buddenhagen * src/drv_imap.c: move greeting response handling into get_cmd_result() the primary purpose of this is getting rid of the "free-standing" buffer_gets() call. 2011-04-03 16:21 Oswald Buddenhagen * src/: drv_imap.c, isync.h, sync.c: docs - insert "separator comments" between driver entry points - document driver API - document sync_vars_t parts that are stored in the sync state header 2011-04-03 16:15 Oswald Buddenhagen * src/drv_imap.c: make imap_exec() result reporting callback-based this makes the IMAP command submission interface asynchronous. the functions still have synchronous return codes as well - this enables clean error return paths. only when we invoke callbacks we resort to refcounting. as a "side effect", properly sequence commands after CREATE resulting from [TRYCREATE]. 2011-07-24 18:27 Oswald Buddenhagen * src/sync.c: rely on the maildir's existence with "SyncState *" now that we open the box first, we know that it will exist at this point. 2011-07-24 18:26 Oswald Buddenhagen * src/drv_maildir.c: validate maildirs more strictly now that "SyncState *" won't create fake mailboxes any more, we can make a full validity check again. 2011-07-23 14:06 Oswald Buddenhagen * src/: drv_imap.c, drv_maildir.c, isync.h, sync.c: split out drv->load() from drv->select() 2011-07-23 14:13 Oswald Buddenhagen * src/drv_maildir.c: make creation of trash folder independent from -C option the trash is not a box which is synced, but a "byproduct" of manipulating synced boxes, so it makes no sense to bind it to the same option. 2012-07-29 23:07 Oswald Buddenhagen * src/drv_imap.c: minor cleanup: use ctx->gen instead of gctx for consistency 2012-07-29 21:15 Oswald Buddenhagen * src/sync.c: make callbacks return early when canceling even after driver->cancel() the store may complete commands successfully. return early in this case, so we don't attempt to continue syncing. 2012-07-29 21:14 Oswald Buddenhagen * src/: drv_imap.c, drv_maildir.c, isync.h, sync.c: fix error paths wrt sync drivers, take 2 synchronous error codes which are passed through callbacks aren't a particularly good idea, after all: latest when the callback does stuff which does not concern the caller, the return code becomes ambiguous. instead, protect the sync_vars object with a refcount when invoking driver functions from loops, as the callbacks they call could invalidate the object and we would have no way of knowing that the loop should be aborted prematurely. the upcoming async imap driver will also need a refcount to protect the cancelation marker of the imap socket dispatcher loop. 2011-04-03 14:29 Oswald Buddenhagen * src/sync.c: don't call cancel() repeatedly on a store erroring command replies will trickle in even after canceling 2012-07-15 10:55 Oswald Buddenhagen * src/: drv_imap.c, drv_maildir.c, isync.h, main.c, sync.c: replace DRV_STORE_BAD with a separate bad_callback() that way we don't have to piggy-back (possibly asynchronous) fatal errors to particular commands. internally, the drivers still use synchronous return values as well, so they don't try to access the invalidated store after calling back. 2012-07-22 15:46 Oswald Buddenhagen * src/sync.c: don't access free'd memory in cancel_sync() as it happens, the 1st round *may* trash svars - if we get the cancelation request after the slave store has already died. 2012-07-22 15:32 Oswald Buddenhagen * src/: drv_imap.c, drv_maildir.c, isync.h, sync.c: make drv->cancel()'s callback have no status code this function is not going to actually execute any commands, so it makes no sense for the callback to have a status code. 2012-06-17 12:52 Oswald Buddenhagen * src/sync.c: don't decode aux pointer on DRV_CANCELED the aux data was already free()d by the error callback by the time we get this status code. 2011-03-20 12:45 Oswald Buddenhagen * src/drv_imap.c: always use return value from get_cmd_result() once we have callback-based error reporting, this will ensure that we don't operate on invalidated data structures. 2010-12-05 15:49 Oswald Buddenhagen * src/drv_imap.c: make response code parse failure of untagged OK/NO/BYE/BAD non-fatal as such, it does not disrupt the data stream 2012-07-15 10:50 Oswald Buddenhagen * src/main.c: de-duplicate code a bit 2010-12-15 18:01 Oswald Buddenhagen * src/drv_imap.c: remove redundant use_ssl variables just use the presence of an SSL object as an indicator. if something goes wrong during the ssl handshake or certificate validation, the socket must be immediately closed anyway. 2010-11-20 22:48 Oswald Buddenhagen * src/isync.h: DRV_SERVER_BAD is and will probably stay unused => trash 2010-11-20 09:17 Oswald Buddenhagen * src/drv_imap.c: after [TRYCREATE], just resend the same command instead of cloning it 2011-03-20 15:27 Oswald Buddenhagen * src/drv_imap.c: use return values from correct set in get_cmd_result() DRV_OK == RESP_OK, so this worked by accident 2010-11-15 09:38 Oswald Buddenhagen * src/drv_imap.c: do away with the dreaded rcaps hack don't pretend that the server has no literal+ for the time of the first relevant command's synchronous execution. instead, enable the lower layer to do the processing by telling it for which commands trashnc ("trash's existence not confirmed") is relevant. 2010-11-15 09:30 Oswald Buddenhagen * src/drv_imap.c: purge imap_store_t::currentnc vestiges we always actually open the mailbox before appending to it, so we obviously know that it exists - that's why the code was already commented out. changing this assumption would significantly complicate matters for little gain, so let's just assume it won't happen. consequently, also don't set param.create when appending to regular mailboxes. 2011-06-13 10:02 Oswald Buddenhagen * src/: drv_imap.c, drv_maildir.c, main.c: move setting of ctx->listed outside the drivers it's essentially an external state flag 2011-04-10 07:58 Oswald Buddenhagen * src/sync.c: de-duplicate error paths makes the code more compact. yay for gotos. 2011-07-23 10:49 Oswald Buddenhagen * src/drv_maildir.c: check return value from close() after write() otherwise we may lose data when quota is exceeded or nfs is in a bad mood. 2012-07-07 15:19 Oswald Buddenhagen * src/: compat/convert.c, drv_imap.c, drv_maildir.c, sync.c: fix a bunch of warnings 2011-03-27 10:06 Oswald Buddenhagen * src/: compat/main.c, drv_imap.c, main.c: avoid preprocessor warnings on missing features: #if => #ifdef 2011-03-12 15:20 Oswald Buddenhagen * src/drv_imap.c: less bizarre code we know that there is only one command in progress, so there is no need to employ tricks to access the last command. 2011-01-23 12:35 Oswald Buddenhagen * src/drv_imap.c: make cram() sane - don't silently fail in release mode (expression with side effects inside assert()) - save some redundand strlen()s by not throwing away known lengths - reorganize the code for legibility 2010-11-20 22:04 Oswald Buddenhagen * src/sync.c: don't compare find_old_done with find_new_total this didn't have any effect as no async drivers currently exist. 2010-12-19 22:33 Oswald Buddenhagen * src/main.c: don't hang if store cannot be opened asynchronously 2011-03-06 22:04 Oswald Buddenhagen * src/drv_imap.c: don't leak SSL objects 2011-03-27 09:01 Oswald Buddenhagen * src/sync.c: add CR after TUID during LF => CRLF conversion 2011-03-27 08:52 Oswald Buddenhagen * src/sync.c: fix (another) out-of-bounds access in CRLF conversion if the header contained no CRs but the body (or the post-TUID part of the header) did, the TUID insertion would add an excess CR, thus overflowing the buffer by one byte. 2010-11-14 16:23 Oswald Buddenhagen * src/mbsync.1: document some breakage 2010-11-14 15:44 Oswald Buddenhagen * src/: compat/convert.c, drv_imap.c, drv_maildir.c: turns out, free(NULL) is just fine ... 2010-10-03 12:31 Oswald Buddenhagen * src/drv_imap.c: fix UIDNEXT handling UIDNEXT *can* be legally zero, so deal with it. -REFMAIL: 4CA62BA1.4020104@lemma.co.uk 2010-10-03 09:53 Oswald Buddenhagen * src/drv_imap.c: don't hang after failed start_tls() we'd send a LOGOUT command in plain text while the server was already expecting an encrypted command, which would typically lead to waiting for more data and thus an indefinite hang. so close the socket immediately instead of letting the normal shutdown path take care of it. inspired by a patch by Steven Flintham. -REFMAIL: 4C9AB98E.3000400@lemma.co.uk 2010-09-26 13:26 Oswald Buddenhagen * src/drv_imap.c: remove useless message don't complain about missing greeting response - we already complained about an unexpected EOF anyway. 2010-04-05 11:15 Oswald Buddenhagen * src/drv_imap.c: assert valid file handles i've seen error logs of the type SSL_write: Bad file descriptor and i simply can't nail it, so go for some more drastic measures. 2010-04-05 11:08 Oswald Buddenhagen * src/drv_imap.c: formatting 2010-04-05 11:08 Oswald Buddenhagen * src/drv_imap.c: beautify error messages don't print the error number - we print the error string anyway, so it adds no value. add some whitespace to the messages as well. 2010-04-05 11:06 Oswald Buddenhagen * src/drv_imap.c: fix uninitialized variable read this is basically a security fix for nonsensical configurations: if the specified CertificateFile did not contain any certificates, we *might* have accepted an arbitrary server certificate. 2010-02-28 21:23 Oswald Buddenhagen * src/: compat/isync.1, mbsync.1: remove mail addresses from man pages apparently, some people don't see the "maintained by" bits, so make them look harder for explicit contact information (to be found in AUTHORS). 2010-02-07 20:20 Oswald Buddenhagen * src/drv_imap.c: fix compile with SSL on Mac OS X patch by Remko Tronçon BUG: 2126899 2010-02-07 16:36 Oswald Buddenhagen * src/compat/: isync.1, main.c: add -P option to isync wrapper not really a backwards compat option, but whatever ... based on a patch submitted long ago by "nobody". BUG: 1433532 2010-02-07 21:13 Oswald Buddenhagen * isync.spec.in: fix rpm spec file -REFMAIL: 20090122213325.GA11572@crow.ths.tcoek12.org 2010-02-07 21:12 Oswald Buddenhagen * Makefile.am: (new?) automake already sets docdir correctly for us 2010-02-07 11:24 Oswald Buddenhagen * .gitignore, Makefile.am, src/.gitignore, src/compat/.gitignore: cvsignore => gitignore 2010-02-07 11:23 Oswald Buddenhagen * Makefile.am, autogen.sh: adjust ChangeLog generation to git now that log generation is cheap, don't store it in the SCM any more. 2010-02-06 18:38 Oswald Buddenhagen * Makefile.am: fix "make distcheck" this makes the deb-clean target shadow build safe 2010-02-06 09:40 Oswald Buddenhagen * src/: compat/main.c, drv_imap.c, isync.h, main.c: add extra verbose mode which dumps the message contents i needed that to debug the line ending issues. maybe it will find other uses as well ... 2010-02-06 09:34 Oswald Buddenhagen * src/: drv_maildir.c, isync.h, sync.c: fix line ending conversion logic imap may very well store messages with LF line endings. only RFC2822 requires CRLF. consequently, preserve the line endings as much as possible unless the mailbox format does not support it (this would be the case for unix mbox - i actually have no idea about maildir). 2010-02-06 09:32 Oswald Buddenhagen * src/sync.c: some more error reporting relating malformed messages 2008-08-31 20:14 Oswald Buddenhagen * src/drv_imap.c: refactoring. main part is killing struct imap_cmd_cb as such. issue_imap_cmd is split into new_imap_cmd and submit_imap_cmd, so the command can be parametrized after it was instanciated. 2008-08-23 07:54 Oswald Buddenhagen * src/: drv_imap.c, sync.c: deal with UIDVALIDITY of 0 properly. -REF: 20080822094543.GA3528@ugly.local 2008-04-13 09:56 Oswald Buddenhagen * src/drv_imap.c: give the implicitly created imap account config the name of the store. 2008-04-13 09:51 Oswald Buddenhagen * src/drv_imap.c: make ssl certificate handling much more useful: - system-wide ca certs are auto-loaded - private certs are accepted even if they are self-signed 2008-04-12 08:58 Oswald Buddenhagen * src/drv_imap.c: - accept unset CertificateFile - print the certificate's fingerprint - make the certificate acceptance prompt much less scary 2008-04-12 08:13 Oswald Buddenhagen * src/drv_imap.c: ignore system flag extensions (\X-...) 2008-03-16 09:09 Oswald Buddenhagen * README: minor updates 2008-02-23 14:18 Oswald Buddenhagen * src/compat/config.c: compat wrapper: don't crash if neither host nor tunnel are specified. fixes: CCMAIL: 449006@bugs.debian.org 2008-02-23 09:37 Oswald Buddenhagen * src/compat/config.c: quote user name in generated config. fixes: CCMAIL: 456775@bugs.debian.org 2008-02-23 09:18 Oswald Buddenhagen * src/main.c: don't overlook 2nd and later single-letter options in last argument. reported by fedora -REF: <1197916586.13945.120.camel@localhost.localdomain> 2008-02-23 09:01 Oswald Buddenhagen * src/: compat/convert.c, drv_maildir.c, mdconvert.c: put pointers to bdb open() into parentheses, so they won't be macro-expanded as libc open. patch by fedora -REF: <1197916586.13945.120.camel@localhost.localdomain> 2008-02-23 08:53 Oswald Buddenhagen * AUTHORS: reshuffle for "contact priority's" sake 2007-09-22 08:45 Oswald Buddenhagen * src/drv_imap.c: don't use #ifdef inside htons() arguments - it can be a macro. -REF: CCMAIL: Scott Gifford 2007-04-04 17:03 Oswald Buddenhagen * Makefile.am: forward port (finally ...): add target for creating signed package 2007-04-04 16:19 Oswald Buddenhagen * src/main.c: #ifdef __linux__ for the crash handler. it compiles on other platforms, but the functionality is bound to linux' /proc structure. 2007-02-10 15:37 Oswald Buddenhagen * src/drv_imap.c: fix crash due to uninited var when parsing IMAPServer. Thanks to CCMAIL: Antoine Reilles REF: <20070118182534.GA22288@arcelot.loria.fr> 2006-12-09 10:39 Oswald Buddenhagen * src/: drv_imap.c, drv_maildir.c, isync.h, sync.c: fix error paths wrt sync drivers 2006-12-09 10:38 Oswald Buddenhagen * src/run-tests.pl: handle abnormal program exit during regtest 2006-12-04 17:47 Oswald Buddenhagen * src/main.c: initialize mvars->t[1] to 1. helps enormously ... :} 2006-11-18 13:17 Oswald Buddenhagen * src/drv_maildir.c: reverse-map to INBOX when encountered during listing. usually this will be a no-op (when putting INBOX in Path, people generally call it INBOX), but better safe than sorry. 2006-11-09 17:57 Oswald Buddenhagen * src/compat/main.c: make compat wrapper default to current user for imap login 2006-11-01 06:19 Oswald Buddenhagen * src/compat/config.c: put INBOX in Maildir 2006-10-24 17:37 Oswald Buddenhagen * src/drv_maildir.c: don't crash on truncating database. seems to affect only some bdb versions (e.g., 4.2). 2006-08-10 07:01 Oswald Buddenhagen * src/sync.c: fix bug in newline conversion causing buffer overflows. this leads to segfaults and has some security impact. 2006-08-10 06:33 Oswald Buddenhagen * src/drv_imap.c: memmove for overlapping mem copies. 2006-07-31 05:30 Oswald Buddenhagen * src/drv_maildir.c: glibc seems to be *really* fucked up. 2006-07-29 11:52 Oswald Buddenhagen * src/: drv_maildir.c, mdconvert.c: work around glibc bug: printf("%.*s", INT_MAX, s) tries to allocate 2G. 2006-06-05 11:59 Oswald Buddenhagen * src/compat/config.c: enable the old account naming scheme to deal with duplicated ip addresses. this is not incompatible - previously, it would just create garbage. 2006-06-05 11:55 Oswald Buddenhagen * src/compat/: config.c, isync.h: create more descriptive account names, so password prompts look sane. the channel names follow the old scheme, though - they are used to compose sync state file names, and i don't feel like writing a migrator for this. 2006-05-28 16:03 Oswald Buddenhagen * src/drv_imap.c: don't crash in imap driver when Host is not specified. 2006-05-28 16:02 Oswald Buddenhagen * src/mbsync.1: be *slightly* more explicit about which options Tunnel makes superfluous. 2006-05-28 15:43 Oswald Buddenhagen * src/: drv_imap.c, mbsync.1: un-document "Host imaps:[...]" syntax and introduce new option UseIMAPS instead. apply ted's patch to support UseIMAPS in conjunction with Tunnel. document that SSLv2 is No Good (TM). 2006-05-28 13:38 Oswald Buddenhagen * src/drv_imap.c: move assigning default port to the place of use 2006-05-27 12:44 Oswald Buddenhagen * src/drv_maildir.c: add comment 2006-05-27 12:43 Oswald Buddenhagen * src/sync.c: seen messages are eligible for expiration even if they are recent in the mailbox. 2006-03-21 20:05 Oswald Buddenhagen * src/main.c: no/empty mailbox name means INBOX 2006-03-21 20:03 Oswald Buddenhagen * src/: drv_imap.c, drv_maildir.c, isync.h, main.c, sync.c, util.c: make the driver model, sync_chans() and sync_boxes() fully async. async drivers to follow ... 2006-03-21 17:50 Oswald Buddenhagen * src/sync.c: unscrew lf=>crlf conversion and tuid insertion 2006-03-21 17:40 Oswald Buddenhagen * src/sync.c: ok, mismerging and not running the reg-tests is lame. unscrew expunging again. 2006-03-21 16:03 Oswald Buddenhagen * src/sync.c: don't enter trash loop if not trashing at all. also, move expunge message where it belongs. not adding info("trashing"), as it will be replaced in a moment anyway. 2006-03-21 15:53 Oswald Buddenhagen * src/: main.c, sync.c: async merge: aggregate most variables of main() & sync_boxes() in main_vars_t resp. sync_vars_t. also some minor var renames, whitespace, comments. 2006-03-21 10:38 Oswald Buddenhagen * src/main.c: split box list preparation from "consumption". 2006-03-21 10:30 Oswald Buddenhagen * src/: isync.h, main.c, sync.c: info() about opening of stores 2006-03-20 20:39 Oswald Buddenhagen * src/drv_imap.c: do not repeatedly get namespace from server. 2006-03-20 20:34 Oswald Buddenhagen * src/drv_imap.c: handle socket() failure and correctly report gethostbyname() failure. 2006-03-20 20:16 Oswald Buddenhagen * src/: drv_imap.c, drv_maildir.c, isync.h, main.c, sync.c, util.c: update copyrights 2006-03-20 19:38 Oswald Buddenhagen * src/: drv_imap.c, drv_maildir.c, isync.h, main.c: move whole responsibility for recycling open stores/server connections to the drivers. 2006-03-20 19:27 Oswald Buddenhagen * src/: drv_imap.c, drv_maildir.c, isync.h, main.c: keep the result of driver->list() and a flag whether it is valid in the store. 2006-03-20 18:36 Oswald Buddenhagen * src/: config.c, isync.h: aggregate all (two ...) drivers in an array instead of naming them in each (one ...) location explicitly. 2006-03-20 17:21 Oswald Buddenhagen * src/drv_imap.c: whitespace and code verbosity 2006-03-20 15:01 Oswald Buddenhagen * src/drv_imap.c: merge imap_t into imap_store_t - there is really no point in having them separated. 2006-03-19 11:29 Oswald Buddenhagen * src/: config.c, drv_imap.c, drv_maildir.c, isync.h, main.c, sync.c, util.c: "fprintf( stderr," => "error(". new functions debugn() and infon() for messages with missing newline; warn() and error() act upon this. 2006-03-19 10:44 Oswald Buddenhagen * src/drv_imap.c: make config parsing more robust against bogus input and report errors more clearly. 2006-02-12 11:42 Oswald Buddenhagen * src/sync.c: factor out box selection from sync_boxes to avoid code dupe 2006-02-11 20:28 Oswald Buddenhagen * src/sync.c: lock the sync state open the journal before opening the master. this is a bit ugly for the "SyncState *" case, as we have to create a directory without making it a maildir right away. however, this makes the code quite a bit simpler to understand and simpler to parallelize. 2006-02-11 20:14 Oswald Buddenhagen * src/drv_maildir.c: don't barf at directories with none of {tmp,new,cur}/ and turn them into maildirs instead. see next commit. 2006-02-11 20:02 Oswald Buddenhagen * src/sync.c: don't commit state file when a fatal error occurs 2006-02-11 19:52 Oswald Buddenhagen * src/sync.c: unbelieveable, but close() can actually fail 2006-02-11 19:48 Oswald Buddenhagen * src/run-tests.pl: add copyright + license 2006-02-09 17:44 Oswald Buddenhagen * acinclude.m4, get-cert, src/compat/config.c, src/compat/convert.c, src/compat/isync.1, src/compat/isync.h, src/compat/main.c, src/compat/util.c, src/config.c, src/drv_imap.c, src/drv_maildir.c, src/isync.h, src/main.c, src/mbsync.1, src/mdconvert.1, src/mdconvert.c, src/sync.c, src/util.c: update fsf's postal address. i think it's sort of useless nowadays anyway, but heck ... 2006-02-05 17:42 Oswald Buddenhagen * src/mbsync.1: typos 2006-02-05 17:39 Oswald Buddenhagen * configure.in: bump version. no, i'm not releasing yet ... :) 2006-02-05 17:38 Oswald Buddenhagen * src/Makefile.am: include run-tests.pl in distribution 2006-02-03 23:43 Oswald Buddenhagen * src/sync.c: and now don't clobber the mails ... 2006-02-03 21:33 Oswald Buddenhagen * src/: drv_imap.c, drv_maildir.c, isync.h, sync.c, util.c: wrap message storing into transactions. nice side effect: drivers don't need to deal with line end conversion any move. 2006-02-02 17:03 Oswald Buddenhagen * src/: isync.h, sync.c: major overhaul of flag change propagation and MaxMessages handling: - wrap message (un)expirations into transactions - no redundand flag propagations in conjunction with expirations - better prepared for the upcoming async operation 2006-02-02 13:48 Oswald Buddenhagen * src/main.c: crash handler that launches gdb. activated when started with -D option. simplifies debugging crashes during the reg-tests. 2006-02-02 11:23 Oswald Buddenhagen * src/sync.c: less cluttered debug output 2006-02-02 11:12 Oswald Buddenhagen * src/sync.c: cosmetics: move around variable declarations and remove obsolete comment 2006-02-02 11:07 Oswald Buddenhagen * src/sync.c: versioned journal. the commands and their meanings change all the time, so better handle that case. ps: yes, i think not upgrading mbsync between interrupting and resuming a run is a reasonable requirement. 2006-02-02 10:44 Oswald Buddenhagen * src/sync.c: make the sync entry search in the journal replay wrap around at the end of the list. the "always forward" assumption is violated in some cases. 2006-02-02 10:25 Oswald Buddenhagen * src/run-tests.pl: much improved journal replay testing. some clenup. 2006-02-02 10:04 Oswald Buddenhagen * src/: run-tests.pl, sync.c: orphan/kill all affected entries after expunge 2006-01-31 13:57 Oswald Buddenhagen * Makefile.am: deal with branches in "make log" 2006-01-30 13:49 Oswald Buddenhagen * src/: isync.h, sync.c: M_EXPIRED -> M_EXPIRE 2006-01-30 13:11 Oswald Buddenhagen * src/sync.c: sanitize S_DEL 2006-01-30 13:01 Oswald Buddenhagen * src/sync.c: remove superfluous temporary rflags from sync_boxes 2006-01-30 11:12 Oswald Buddenhagen * src/: isync.h, sync.c: now that messages know their sync records, M_SYNCES is superfluous. 2006-01-30 10:26 Oswald Buddenhagen * src/: isync.h, sync.c: establish bi-directional mapping between mails and sync records. use it to merge the --renew case into the --new case. 2006-01-30 09:33 Oswald Buddenhagen * src/sync.c: declaring ex[M] instead of ex[2] is, indeed, no good. long live watchpoints. 2006-01-29 18:40 Oswald Buddenhagen * src/compat/main.c: whoops - 'isync -w' would write .mbsyncrc to a wrong directory 2006-01-29 15:52 Oswald Buddenhagen * src/sync.c: move fetching new messages in front of syncing old entries. this alone does not buy us a whole lot ... 2006-01-29 15:48 Oswald Buddenhagen * src/run-tests.pl: test for journalling and journal replay. 2006-01-29 15:46 Oswald Buddenhagen * src/: isync.h, main.c, sync.c: undocumented flag -J to skip committing the new sync state. 2006-01-29 14:46 Oswald Buddenhagen * src/: drv_imap.c, isync.h, main.c, sync.c, util.c: merge Quiet, Verbose & Debug into DFlags 2006-01-29 11:49 Oswald Buddenhagen * src/: isync.h, sync.c: M_NOT_SYNCED => M_SYNCED. now that sync records know their messages, it is simpler to track the positive case. 2006-01-29 11:35 Oswald Buddenhagen * src/sync.c: move driver options composition below journal replay - it might make additional actions necessary (it doesn't, yet). 2006-01-29 11:22 Oswald Buddenhagen * src/: drv_imap.c, drv_maildir.c, isync.h, sync.c: split driver->prepare into ->prepare_opts and ->prepare_paths 2006-01-25 06:35 Oswald Buddenhagen * src/drv_imap.c: #include limits.h (for INT_MAX) REF: 2006-01-13 16:10 Oswald Buddenhagen * src/sync.c: less confusing uid ranges in debug 2006-01-12 06:36 Oswald Buddenhagen * configure.in, src/drv_imap.c: solaris 10 fix: use sys/filio.h for FIONREAD. untested. REF: <20060111215014.GA601@49.180.97-84.rev.gaoland.net> 2006-01-08 19:25 Oswald Buddenhagen * src/run-tests.pl: adjust to: omit flags other than "deleted" when expunging target. 2006-01-03 09:28 Oswald Buddenhagen * src/run-tests.pl: collect stderr as well. 2005-12-29 13:08 Oswald Buddenhagen * src/sync.c: don't record we synced flags if we didn't. 2005-12-28 20:45 Oswald Buddenhagen * src/util.c: have to flush debug as well ... 2005-12-28 20:05 Oswald Buddenhagen * src/sync.c: of course F_DELETED will have been added to expired slave messages, so don't complain about it. 2005-12-28 19:17 Oswald Buddenhagen * src/sync.c: put message references into the sync records. match up the uids after opening the boxes instead of "sort-of-on-demand" - this is much simpler. match from messages to sync records, not the other way round - makes the debug output shorter, as the separate dump_box() is gone now. 2005-12-28 19:10 Oswald Buddenhagen * src/sync.c: "reformat" S_EXP_S setting logic for understandability. 2005-12-28 11:07 Oswald Buddenhagen * src/main.c: whoops 2005-12-28 10:02 Oswald Buddenhagen * src/: config.c, isync.h, main.c, sync.c: - instead of having {m,s}foo, we have foo[2] now, so we can do everything with loops instead of symmetric function calls - added some const 2005-12-27 17:44 Oswald Buddenhagen * src/run-tests.pl: show debug output on error. 2005-12-27 17:31 Oswald Buddenhagen * src/run-tests.pl: make the error case output more useful by dumping the entire data set. 2005-12-26 16:02 Oswald Buddenhagen * src/run-tests.pl: fix error message 2005-12-26 16:02 Oswald Buddenhagen * src/run-tests.pl: add expiration tests 2005-12-26 16:01 Oswald Buddenhagen * src/run-tests.pl: add MaxSize tests 2005-12-26 16:00 Oswald Buddenhagen * src/run-tests.pl: when dumping mailboxes, sort by uid 1st. 2005-12-26 15:58 Oswald Buddenhagen * src/run-tests.pl: detect excess messages after sync 2005-12-26 15:57 Oswald Buddenhagen * src/run-tests.pl: sync state reader: - grok negative uids - more robust 2005-12-26 15:54 Oswald Buddenhagen * src/run-tests.pl: don't eat array lead-in on empty arrays 2005-12-26 15:02 Oswald Buddenhagen * src/sync.c: why would somebody manipulate an expired message? right, he wouldn't: he would either expunge the mailbox or configure his MUA to hide trashed messages. consequently don't sync expired message flags, let alone interpret them in a special way. one special feature remains, though: if a non-expunged expired message is flagged on the master, it will be unexpired on the slave. i'm not sure whether i should remove or document this feature. 2005-12-26 14:55 Oswald Buddenhagen * src/sync.c: message tweaks 2005-12-23 10:22 Oswald Buddenhagen * src/run-tests.pl: more logical order 2005-12-22 18:06 Oswald Buddenhagen * src/: .cvsignore, run-tests.pl: add some regression testing. 2005-12-22 14:59 Oswald Buddenhagen * src/sync.c: fix sync entries not being purged due to c&p error. 2005-12-21 13:04 Oswald Buddenhagen * src/drv_maildir.c: less confusing error message on invalid mailbox. 2005-12-18 14:10 Oswald Buddenhagen * src/config.c: it's beyond me what this memset was supposed to do ... 2005-12-18 13:41 Oswald Buddenhagen * src/: config.c, main.c: trailing whitespace 2005-12-17 13:47 Oswald Buddenhagen * src/drv_imap.c: revert 1.8 - what was i smoking?! the CREATE argument is already quoted; we just extracted it from the previous command. 2005-09-29 21:07 Oswald Buddenhagen * src/drv_maildir.c: make flag changes unset "new" status - unless a ghost is acting in the background, a flag change indicates that the message was at least noticed. 2005-09-29 21:05 Oswald Buddenhagen * src/sync.c: don't call the driver's set_flags() if the flags did not change at all. 2005-09-21 16:14 Oswald Buddenhagen * src/drv_imap.c: 64-bit cleanness 2005-03-28 10:43 Oswald Buddenhagen * src/drv_imap.c: quote CREATE argument 2005-03-28 10:26 Oswald Buddenhagen * configure.in: bump version 2005-03-28 10:26 Oswald Buddenhagen * src/drv_maildir.c: fix inverted condition leading to endless loop when message is changed while isync is running. 2004-11-13 09:19 Oswald Buddenhagen * src/sync.c: cope with out-of-disk-space halfways gracefully (that is, don't clobber the sync state including the journal, but exit immediately). 2004-10-17 16:31 Oswald Buddenhagen * AUTHORS: sf.net -> sourceforge.net. otherwise the list-post is different from the actual address, which makes mutt add two to addresses on list-reply ... 2004-10-17 15:34 Oswald Buddenhagen * src/drv_imap.c: ignore user-defined flags (for now). also, split off the backslash from the "core" flag names. 2004-10-17 09:00 Oswald Buddenhagen * src/drv_imap.c: fix segfault due to wrong pointer being passed to parse_response_code. inspired by Raimar Döffinger 2004-10-17 08:30 Oswald Buddenhagen * src/drv_imap.c: remove spurious crlf during cram auth. not sure that this instance of socket_write should be (re)moved, but as long as the .cont callback is used only for this ... investigation & patch by Mike Delaney. 2004-09-24 08:45 Oswald Buddenhagen * Makefile.am: install supplementary doc files. REF: 38C5E3CF30C73C4984F41AE8786C852AB739@khyron.ads.cs.umass.edu 2004-09-20 11:31 Oswald Buddenhagen * src/drv_maildir.c: use legacy flock() only on linux. at least on OS X flock aliases to fcntl. 2004-09-20 11:28 Oswald Buddenhagen * src/: compat/main.c, drv_imap.c, isync.h, util.c: stdarg.h at the right places 2004-09-15 09:33 Oswald Buddenhagen * README: update c-client compatibility 2004-09-15 09:06 Oswald Buddenhagen * src/drv_maildir.c: when storing \seen messages, don't set the \recent flag on them. could well be that this is incorrect, but some mailers need it that way. when trashing messages, preserve their \recent status as well. 2004-09-15 08:44 Oswald Buddenhagen * configure.in: whoops, wrong define 2004-09-08 16:40 Oswald Buddenhagen * configure.in: don't encode maturity in version number 2004-09-08 16:38 Oswald Buddenhagen * Makefile.am: optimize rpms for i686 2004-09-08 16:28 Oswald Buddenhagen * configure.in: sanitize the OpenSSL detection 2004-09-08 16:14 Oswald Buddenhagen * src/drv_imap.c: stddef.h for offsetof 2004-09-08 14:52 Oswald Buddenhagen * src/drv_maildir.c: first check _both_ bounds, then compare ... 2004-09-07 11:59 Oswald Buddenhagen * src/sync.c: print name of mailbox being opened. 2004-08-13 11:03 Oswald Buddenhagen * src/drv_imap.c: fix -C for imap mailboxes: - SELECT does not return [TRYCREATE] - fix bit field truncation 2004-06-17 13:44 Oswald Buddenhagen * configure.in: A{C,S}_HELP_STRING aliasing tricks. 2004-05-23 16:39 Oswald Buddenhagen * src/drv_maildir.c: store new UIDVALIDITY immediately after initializing it 2004-04-27 20:23 Oswald Buddenhagen * src/compat/main.c: old -l is new -l -C 2004-04-26 14:48 Oswald Buddenhagen * src/compat/: config.c, isync.h, main.c: full support for absolute paths in Mailboxes 2004-04-26 14:09 Oswald Buddenhagen * src/compat/config.c: strip $HOME and ~ from Mailbox paths 2004-03-29 22:32 Oswald Buddenhagen * src/: compat/util.c, util.c: fix return values of asprintf replacement. 2004-03-29 06:52 Oswald Buddenhagen * src/compat/: config.c, isync.1, isync.h, main.c: unscrew --delete by merging it into the config file. merge --expunge as well for symmetry. 2004-03-27 16:07 Oswald Buddenhagen * .cvsignore, Makefile.am, README, configure.in, isync.spec.in, src/.cvsignore, src/Makefile.am, src/compat/.cvsignore, src/compat/Makefile.am, src/compat/config.c, src/compat/convert.c, src/compat/isync.1, src/compat/isync.h, src/compat/isyncrc.sample, src/compat/main.c, src/compat/util.c, src/config.c, src/cram.c, src/dotlock.c, src/dotlock.h, src/drv_imap.c, src/drv_maildir.c, src/imap.c, src/isync.h, src/list.c, src/maildir.c, src/main.c, src/mbsync.1, src/mbsyncrc.sample, src/mdconvert.1, src/mdconvert.c, src/sync.c, src/util.c: The Big Rewrite. too many change to list them all. as opposed to earlier threats, BerkDB was not entirely dropped; i suppose the isync 0.7 -> 0.8 change had a reason, so i added an alternative UID storage scheme. note that BDB 4.0 is not sufficient, as the db->open function changed in an incompatible way ... i updated the debian packaging except for a changelog entry. note that i removed the upgrade blurb, as upstream now has a smooth upgrade path down to at least isync 0.4. 2004-03-26 16:34 Oswald Buddenhagen * get-cert: excessively secure temp file creation. more user friendliness. 2004-02-07 15:36 Oswald Buddenhagen * src/dotlock.c: portability: don't rely on struct flock layout 2004-02-01 16:44 Oswald Buddenhagen * .cvsignore: shht 2004-02-01 16:27 Oswald Buddenhagen * src/: main.c, sync.c: once again: (slightly) better output. make maildir flag setting failure non-fatal. maildir sucks ... 2004-01-31 01:01 Oswald Buddenhagen * src/: imap.c, isync.h: more sophisticated CAPABILITY handling. also, don't issue the command if the initial response already had it in the status code. 2004-01-30 23:39 Oswald Buddenhagen * src/imap.c: don't ask for NAMESPACE if Folder was specified 2004-01-30 23:35 Oswald Buddenhagen * src/: imap.c, isync.h: following the "screw murphy" principle and commiting untested patch: obey LOGINDISABLED 2004-01-27 21:01 Oswald Buddenhagen * src/imap.c: PREAUTH cannot come out of the blue 2004-01-27 20:58 Oswald Buddenhagen * src/imap.c: cleanup around parse_fetch 2004-01-27 20:50 Oswald Buddenhagen * src/: imap.c, isync.h, main.c: make Tag int, move it to imap.c 2004-01-27 00:11 Nicolas Boullis * acinclude.m4, configure.in: Add a --disable-maintainer-mode option to configure. 2004-01-20 01:55 Oswald Buddenhagen * src/imap.c: don't use STARTTLS for PREAUTH connections. uw-imap doesn't seem to like it, and it does not make too much sense anyway - i think - state converse opinions now. 2004-01-20 01:27 Oswald Buddenhagen * Makefile.am: exclude ChangeLog (do'h), NEWS and TODO when creating ChangeLog. exclude debian/ as well, based on the fact that it already has a detailed log - is that ok with everybody? 2004-01-18 02:22 Oswald Buddenhagen * isync.1, src/imap.c, src/isync.h, src/maildir.c, src/main.c, src/sync.c: another message output cleanup, still not perfect (info messages will be interleaved with progress dots). support specifying -q twice to suppress warnings as well. 2004-01-17 11:38 Oswald Buddenhagen * isync.1: document mua interaction 2004-01-16 10:11 Oswald Buddenhagen * AUTHORS: credit where credit is due. are the comments satisfactory for everybody? 2004-01-15 03:51 Theodore Ts'o * get-cert: Script that can be used to extract the server's certificate from an IMAP server. 2004-01-15 02:23 Oswald Buddenhagen * configure.in: remove useless define and more verbose error message. 2004-01-13 03:56 Theodore Ts'o * configure.in: Use a more sophisticated test for the existence of libdb that works for berk_db 4.0. 2004-01-12 01:49 Oswald Buddenhagen * configure.in: bah, forgot to remove debian/Makefile.in from AC_OUTPUT. :} kde's overly sophisticated build system does that automatically ... 2004-01-12 01:24 Theodore Ts'o * src/: imap.c, isync.h, main.c: Optimized isync by not fetching the sizes of messages if they are unneeded (i.e., if MaxSize is not specified in the config file). Patch and idea originally from Nicolas Boullis , modified/polished by Theodore Ts'o per comments by Oswald Buddenhagen. 2004-01-12 00:52 Oswald Buddenhagen * configure.in, src/isync.h, src/maildir.c, src/sync.c: sync uid database after every message. this is accompanied by a dbm -> db4 migration. patch by theodore, with some final polishing by me. 2004-01-12 00:38 Oswald Buddenhagen * Makefile.am: use ../CVSROOT/accounts for UID mapping in ChangeLog. 2004-01-12 00:36 Oswald Buddenhagen * AUTHORS: be more explicit about contact address 2004-01-11 12:38 Oswald Buddenhagen * .cvsignore: new stuff 2004-01-11 12:35 Oswald Buddenhagen * Makefile.am: getting rid of Makefile.am in debian/ - it seems to be non-standard and is a pita to maintain anyway. instead, make distdir and distclean depend on a partial debian-clean. 2004-01-11 11:53 Oswald Buddenhagen * autogen.sh: don't call configure 2004-01-09 20:43 Oswald Buddenhagen * src/main.c: ignore anything that does not look remotely like a maildir when collecting mailboxes for OneToOne. 2003-12-07 15:37 Oswald Buddenhagen * isyncrc.sample: add sample CertificateFile 2003-12-07 15:36 Oswald Buddenhagen * src/imap.c: add trailing space to password prompt 2003-12-07 15:34 Oswald Buddenhagen * src/main.c: make imaps: on the command line adjust the port and ssl options as well 2003-12-07 15:09 Oswald Buddenhagen * configure.in: bump version 2003-12-02 02:53 Oswald Buddenhagen * src/imap.c: echo the mailbox the password is for 2003-11-11 03:02 Oswald Buddenhagen * AUTHORS: be more explicit about maintainership, as people don't seem to get it. 2003-09-02 12:06 Oswald Buddenhagen * isync.1: minor additions 2003-07-02 17:18 Oswald Buddenhagen * src/imap.c: fix crash when syncing multiple mailboxes over a Tunnel 2003-05-14 13:42 Oswald Buddenhagen * isync.1: minor 2003-05-07 00:06 Oswald Buddenhagen * .cvsignore, Makefile.am, autogen.sh, configure.in, src/config.c, src/cram.c, src/dotlock.c, src/imap.c, src/isync.h, src/list.c, src/maildir.c, src/main.c, src/sync.c: - make it work without SSL - switch from -Ds in Makefile to config.h - small header cleaup 2003-05-07 00:04 Oswald Buddenhagen * isync.spec.in: make it actually work 2003-05-06 02:17 Oswald Buddenhagen * Makefile.am: minors 2003-05-06 02:15 Oswald Buddenhagen * README: i'm bored :) 2003-05-05 17:58 Oswald Buddenhagen * src/: config.c, isync.h, main.c: don't free any config strings - who cares for a few bytes? this fixes some crashes at exit. 2003-05-05 17:17 Oswald Buddenhagen * Makefile.am: switch ChangeLog generation to cvs2cl 2003-05-05 13:43 Oswald Buddenhagen * isync.1: minor fixes 2003-05-05 13:41 Oswald Buddenhagen * configure.in: cleanup 2003-05-05 13:24 Oswald Buddenhagen * src/main.c: accumulate status over multiple mailboxes, i.e., don't abort after first failure 2003-05-05 12:54 Oswald Buddenhagen * src/imap.c: fix imaps: 2003-02-27 18:43 Oswald Buddenhagen * src/sync.c: ignore \Recent, as it is voided by the syncronization run itself. 2002-12-28 15:31 Oswald Buddenhagen * src/: config.c, cram.c, imap.c, isync.h, list.c, maildir.c, main.c, sync.c: - update copyrights. 2003 didn't begin yet, but who cares? :) 2002-12-28 04:14 Oswald Buddenhagen * isync.1: - fixed typo - updated maintainer and location 2002-12-28 04:12 Oswald Buddenhagen * src/: maildir.c, sync.c: - update isyncmaxuid properly 2002-12-28 04:04 Oswald Buddenhagen * src/config.c: - fixed two crashes 2002-12-28 04:02 Oswald Buddenhagen * src/imap.c: - handle bogus search responses more gracefully 2002-12-28 04:00 Oswald Buddenhagen * src/imap.c: - workaround imap server bug: lock files are no mailboxes 2002-12-28 03:58 Oswald Buddenhagen * src/: imap.c, sync.c: - improve console output 2002-12-28 03:11 Oswald Buddenhagen * .cvsignore: - ssht! 2002-12-28 03:05 Oswald Buddenhagen * .cvsignore, AUTHORS, Makefile.am, README, autogen.sh, configure.in, isync.spec.in, src/.cvsignore, src/Makefile.am, src/config.c, src/cram.c, src/dotlock.c, src/dotlock.h, src/imap.c, src/isync.h, src/list.c, src/maildir.c, src/main.c, src/sync.c: - took over maintenance - moved to sourceforge - reorganized cvs structure 2002-10-30 02:31 Michael Elkins * config.c, cram.c, dotlock.c, dotlock.h, imap.c, isync.1, isync.h, list.c, maildir.c, main.c, sync.c: Updated the copyright notice to allow an exception for linking with OpenSSL, which has a non-GPL compatible license. 2002-10-30 02:23 Michael Elkins * .cvsignore, config.c, imap.c, isync.1, isync.h, maildir.c, main.c, sync.c: Bunch 'o patches from Oswald Buddenhagen: i implemented some cool stuff (tm). first, the long missing "create server-side missing mailboxes". -C now creates both local and remote boxes; -L and -R create only local/remote. second, i implemented a 1:1 remote:local folder mapping (-1) with an optional INBOX exception (inbox/-I). the remote folder is specified with the folder keyword (or -F switch) and takes precedence over the namespace setting. the local directory with the mailboxes can now be specified on the command line, too (-M). another patch: - made the -1 switch settable permanently (OneToOne). after all, you usually define your mailbox layout once forever. removed -A, as it is semantically -a modified by -1. - cleaned up message output a bit. still, the quiet variable should be used throughout the program. at best, create some generic output function, which obeys a global verbosity level variable. - optimized + cleaned up configuration parser slightly - minor cleanups add an (almost) unique id to every uploaded message and search for it right after. i thought about using the message-id, but a) it is not guaranteed to be unique in a mailbox (imagine you edit a mail and store the dupe in the same box) and b) some mails (e.g., postponed) don't even have one. a downside of the current implementation is, that this id-header remains in the mailbox, but given that it wastes only 27 bytes per mail and removing it would mean several roundtrips more, this seems acceptable. i changed the line-counting loop to use a mmapped file instead of reading it in chunks, as it makes things simpler and is probably even faster for big mails. the amount of goto statements in my code may be scary, but c is simply lacking a multi-level break statement. :) this is the "shut up" patch. :) it makes the -q option consequent, so to say. additionally it adds an -l option which gathers all defined/found mailboxes and just outputs the list. don't ask what i need it for. ;) 2002-10-30 02:01 Michael Elkins * maildir.c: fixed missing closedir() call (Joey Hess) 2002-06-27 03:55 Michael Elkins * imap.c: explicitly set global.pass to NULL when getpass() returns an empty string. 2002-06-27 03:51 Michael Elkins * imap.c: Oswald Buddenhagen * fix imap_open() brokeness with PREAUTH (missed hunk from previous patch) 2002-06-22 17:06 Michael Elkins * dotlock.c, imap.c: fixed errors introduced by ME when hand-applying Oswald Nuddenhagen's patch. 2002-06-22 01:21 Michael Elkins * autogen.sh, dotlock.c, imap.c, isync.h, main.c: Patch from Oswald Buddenhagen - move prompt for password to imap_open() - don't ask for global password in PREAUTH state - use socketpair() to create one full-duplex fd in tunnel mode instead of two half-duplex pipes - don't set lck.l_pid in fcntl() call (its read-only) - use F_SETLK instead of F_SETLKW to avoid infinite waiting - use "$@" in autogen.sh to get proper word expansion 2002-06-21 00:26 Michael Elkins * configure.in, isync.h: Fixed to compile under FreeBSD 4.6-RELEASE. Must include ndbm.h rather than db.h. 2002-06-20 23:33 Michael Elkins * Makefile.am, dotlock.c, dotlock.h, maildir.c: remove debian/files move dotlocking code to dotlock.c. dotlocking code fixed to ignore whether or not the lockfile exists on open(). we only care about whether fcntl() was able to lock it. 2002-06-19 02:31 Michael Elkins * sync.c: Don't bother uploaded messages marked deleted when we are going to expunge. 2002-06-19 01:11 Michael Elkins * AUTHORS, imap.c, maildir.c: fixed unused var warning in imap_open() locking cleanups from Oswald Buddenhagen * don't need to stat the lockfile since it will always be size 0 * only remove lockfile when we actually succeeded in locking 2002-06-19 00:44 Michael Elkins * Makefile.am: Debian package cleanups from Oswald Buddenhagen 2002-06-18 06:37 Michael Elkins * README, isync.1, isync.h, maildir.c, main.c, sync.c: updated URL for project fixed segmentation fault caused by double free() when an error occurred during the IMAP transmission. fixed bug where isync could not handle a 0 value UIDVALIDITY 2002-04-19 19:43 Michael Elkins * config.c, configure.in, imap.c, isync.1, isync.h, isyncrc.sample, main.c: PREAUTH support from Oswald Buddenhagen Added Tunnel directive to allow the user to specify a shell command to run to set up an IMAP connection in place of a TCP socket (eg., to run over an SSH session). 2002-01-28 19:39 Michael Elkins * isync.spec.in: post 0.8 release commit 2002-01-28 19:34 Michael Elkins * configure.in: check for dbm_open() in libc and libdb 2002-01-17 19:33 Michael Elkins * sync.c: don't bother renaming the message file if we are about to unlink() it 2002-01-16 22:23 Michael Elkins * AUTHORS, Makefile.am, sync.c: remove tilde backup files for distclean fixed indentation added full name to AUTHORS reformated NEWS blurb for 0.8 2002-01-16 22:13 Michael Elkins * maildir.c, sync.c: sync_mailbox() did not update the msg struct when flags were changed, causing the expunge command to fail remove bogus strfcpy() line 2002-01-16 21:51 Michael Elkins * Makefile.am, configure.in: added debian build files dist target so that people can use them to build their own .deb packages without having to use CVS 2002-01-16 21:43 Michael Elkins * isync.1, maildir.c, sync.c: added debian build files fixed indentation added bug note to manpage about db file format not being architecture independent 2002-01-16 21:22 Michael Elkins * maildir.c, sync.c: remove the uid from the db when a message is deleted from the maildir optimize db fetch/store to not copy the base filename 2002-01-16 19:47 Michael Elkins * config.c, configure.in, cram.c, imap.c, isync.1, isync.h, list.c, maildir.c, main.c, sync.c: updated year in copyright notice the uid for each message in the maildir is now stored in a dbm database rather than the filename. this change was necessary because isync became confused if you copied a message to another folder, in which case the uid was invalid. as a result of the above change, isync now acquires a mutex on the mailbox to protect the dbm database from concurrent access. main() was reworked to continue gracefully when an error is encountered, and to always call maildir_close() so that the lock can be disabled, and the database closed. 2001-11-20 18:28 Michael Elkins * Makefile.am, isync.spec.in: post 0.7-release commit 2001-11-20 18:06 Michael Elkins * Makefile.am, isync.1, isync.h, maildir.c, main.c: added --create/-C command line option to force creation of the local maildir-style mailbox if nonexistent debug.h was not included in isync_SOURCES in Makefile.am 2001-11-19 19:41 Michael Elkins * Makefile.am, config.c, configure.in, isync.h, list.c, main.c: added memory debugging code fixed memory leak in free_list() free memory associated with global settings on exit 2001-11-16 21:23 Michael Elkins * cram.c, imap.c, isync.h, sync.c: remove c++ style comments use %lu and cast off_t to unsigned long in printf() 2001-11-15 23:59 Michael Elkins * config.c, isync.1, isync.h, main.c, sync.c: Added MaxMessages patch from Eivind Eklund . config_defaults() can just use memcpy() instead of assigning each struct member individually. config_defaults() can be declared static 2001-11-14 17:40 Michael Elkins * config.c, configure.in: move strndup() code into config.c for less complexity change AC_REPLACE_FUNC(strndup) to AC_CHECK_FUNCS(strndup) sed expression checking for gcc-3.0 should be quoted beccause it fails under Solaris 2.7 2001-11-13 00:36 Michael Elkins * config.c, sync.c: strndup() could return a non-NULL terminated string size_t should be printed with %lu when expending tildes (~), an extra slash was inserted after the user's home directory 2001-11-12 23:03 Michael Elkins * isync.h, maildir.c, main.c: merge maildir_sync() and maildir_close(). the maxuid in a maildir still needs to be updated in --fast mode, and the sync code already checks to see if any changes were made to the mailbox. 2001-11-09 00:35 Michael Elkins * README: add FreeBSD to the list of tested platforms 2001-11-09 00:23 Michael Elkins * config.c, configure.in, imap.c, maildir.c: update version to 0.7 detect short write in write_strip() fix compilation warnings with gcc-2.95.4 2001-10-31 19:50 Michael Elkins * configure.in, imap.c, isync.h, main.c, sync.c: set compiler warnings for gcc-3.0 as well display message with count of uploaded messages --quiet now supresses warnings in sync_mailbox() fixed compiler warnings with -Wshadow 2001-10-31 06:06 Michael Elkins * isync.1: post 0.6 commit 2001-10-30 22:57 Michael Elkins * README, configure.in: add strndup replacement function for systems which lack it 2001-10-03 17:10 Michael Elkins * Makefile.am, maildir.c: fixed broken code in maildir_clean_tmp() 2001-10-03 16:48 Michael Elkins * maildir.c: added code to clean the tmp directory in a maildir to comply with maildir(5) 2001-10-03 06:32 Michael Elkins * config.c: forgot to add code to parse the `Delete' option 2001-10-03 06:18 Michael Elkins * main.c: forgot conditional #if HAVE_LIBSSL around setting of .use_imaps in main() from command line arguments 2001-10-03 06:15 Michael Elkins * main.c: update Copyright printed by --help add compile time option list to --help output 2001-10-03 05:42 Michael Elkins * config.c, isync.1, isync.h, isyncrc.sample, main.c, sync.c: added `Delete' configuration option to force -d option sync_mailbox() didn't consider MaxSize == 0 to mean "unlimited". load_config() needs to print a newline in its error messages since next_arg() kills the newline of the line that was read out of the config file. 2001-10-03 00:01 Michael Elkins * imap.c, sync.c: fixed maildir message filenames to comply with the maildir(5) specification. fixed write_strip() and imap_fetch_message() to check the return code of write() and fsync() to comply with maildir(5) spec. 2001-10-02 23:43 Michael Elkins * main.c: the `Expunge' config directive didn't work since only the -e command line argument was consulted. 2001-10-02 22:46 Michael Elkins * config.c, imap.c, isync.h: we should issue a CAPABILITY even if we aren't going to use ssl/tls so that cram-md5 auth still works. 2001-07-18 18:56 Michael Elkins * config.c: find_box() should attempt to expand all filenames if none of the other methods found a match. 2001-07-18 18:49 Michael Elkins * config.c, isync.h, maildir.c: fixed to not expand filenames until they are used inside of maildir_open(), so that aliases are not required for simple filenames. [re: http://bugs.debian.org/102255] 2001-06-22 23:30 Michael Elkins * main.c: --host option didn't check for imaps: prefix 2001-06-21 20:45 Michael Elkins * main.c: fixed core when specifying multiple mailboxes on the command line 2001-06-18 21:38 Michael Elkins * configure.in, imap.c, isync.1: handle untagged responses in imap_fetch_message() so that it doesn't bomb out if new mail arrives while in the process of downloading noted in BUGS section of man page that if new mail arrives after the initial message list has been retrieved from the IMAP server, that new mail will not be fetched until the next invocation of isync. 2001-06-18 17:49 Michael Elkins * config.c, imap.c, isync.h, main.c: isync should continue to process additional mailboxes even if there is an error with a previous mailbox. added -a (--all) flag to synchronize all mailboxes defined in ~/.isyncrc 2001-02-28 01:02 Michael Elkins * config.c, imap.c: fixed compiler warnings under Solaris 2.7 2001-02-19 18:44 Michael Elkins * cram.c, imap.c, maildir.c: rfc2595 compliance patch from Daniel Resare - CAPABILITY should be reissued after starting TLS since the previous call was not protected 2001-02-14 20:46 Michael Elkins * config.c, imap.c, isync.1, main.c, sync.c: patch from Daniel Resare : 1 giving a path to a nonexistant rc-file with the -c argument dumps core The patch adds a check to ensure that the given rc-file is accessible 2 the error messages given from failed openssl calls are bogus The handles the error from SSL_connect () correctly. The bug is understndable since the error handling in openssl is quite obfuscated. Good news is that the documentation manapges has been greatly updated in the latest version (0.9.6). See in particular err(3), ERR_get_error(3) and SSL_get_error(3). Please note that possible SSL_ERROR_SSL type errors from SSL_read() and SSL_write() is not handled. This should also be fixed. 3 connecting using the STARTTLS command with an imap server that is configured only to accept the TLSv1 protocol gives an error because isync sends an SSLv2 Hello message for backwards compability. (This is the case with the uw-imap 2000 that ships with redhat-7.0) I've read RFC2595 several times to see if it says something about compability SSL2/SSL3 hello messages but can't find anything. IMHO the correct thing to do is change the default to not use SSL2/3 compability hello when using the STARTTLS command but use it if the imaps port is used. The patch implements this change 4 repeated calls to SSL_CTX_set_options overwrites the old settings (the values needs to be ORed together) fixed in the patch patch from me@mutt.org: \Recent messages were put in the cur/ directory instead of new/ give error message when the LOGIN command fails 2001-02-01 23:35 Michael Elkins * imap.c: patch from Daniel Resare - don't initialize ssl support if none of use_sslv* is enabled 2001-01-26 20:21 Michael Elkins * imap.c, isync.h: include for off_t patch from "lorenzo martignoni" - fixed uploading of message to IMAP server 2001-01-24 07:09 Michael Elkins * config.c, cram.c, imap.c, isync.1, list.c, maildir.c, main.c, sync.c: fixed cram compilation error under bsd updated man page 2001-01-16 19:45 Michael Elkins * config.c, imap.c, isync.1, isync.h, main.c: added support for tilde (~) expansion in the `Mailbox' and `CertificateFile' configuration directives added `Maildir' configuration command to specify the default location of the user's mailboxes. If a relative path is used in a `Mailbox' command, this path is used as a prefix. 2001-01-11 10:21 Michael Elkins * configure.in, imap.c, isync.h: set imap->prefix to be the namespace prefix update version to 0.5 fixed compilation warnings in imap.c 2001-01-11 10:13 Michael Elkins * Makefile.am, config.c, imap.c, isync.1, isync.h, isyncrc.sample, main.c, sync.c: broke config code into config.c added support for uploading local messages with no UID to the IMAP server added Expunge configuration option added CopyDeletedTo configuration option 2001-01-09 20:09 Michael Elkins * maildir.c, sync.c: always put changed messages in the cur/ subdirectory since they are no longer new. don't set \Seen implicitly for messages in the cur/ folder. Require the S flag on the message since Mutt will move Old (unread, but not recent) messges into cur/. 2001-01-08 09:45 Michael Elkins * Makefile.am, main.c: patch from Hugo Haas -c was not specified in the getopt*() calls set global password to the one the user inputs and use that as the default for remaining mailboxes 2001-01-05 21:20 Michael Elkins * configure.in: added --with-ssl-dir to specify an alternate installation of OpenSSL 2000-12-31 22:39 Michael Elkins * isync.spec.in: pre 0.4 commit. updated rpm spec file 2000-12-31 22:37 Michael Elkins * sync.c: display how many messages were fetched from the server 2000-12-31 22:17 Michael Elkins * imap.c: fixed compilation error with no libssl support ("lorenzo martignoni" ) 2000-12-28 18:44 Michael Elkins * main.c: fixed config parser to accept arbitrary whitespace 2000-12-27 21:16 Michael Elkins * imap.c: use imap_close to terminate a connection in imap_open() 2000-12-27 21:14 Michael Elkins * imap.c, isync.1, isync.h, maildir.c, main.c: allow leading whitespace in config files now possible to sync multiple mailboxes by specifying multiple aliases on the command line. IMAP connections are reused if possible. don't initialize ssl unless we are going to use it. 2000-12-23 21:57 Michael Elkins * imap.c, isync.h: don't use NAMESPACE unless the server supports it 2000-12-23 00:02 Michael Elkins * Makefile.am, README, cram.c, imap.c, isync.h: added CRAM-MD5 authentication support. parse server capability string to determine if STARTTLS is available 2000-12-22 21:22 Michael Elkins * README, imap.c, isync.1, isync.h, main.c: isync-brokenservers.diff (Jeremy Katz ) adds support for disabling NAMESPACE, and disable various flavors of TLS/SSL for use with some broken IMAP servers. 2000-12-22 19:30 Michael Elkins * imap.c, sync.c: prompt user if they wish to continue if the server's X.509 certificate can't be verified. sync_mailbox should consider uid == 0 to be "unknown" 2000-12-22 15:48 Michael Elkins * main.c, sync.c: fixed sync_mailbox() to correctly write new messages to the local maildir box (Thomas Roessler ) 2000-12-22 15:24 Michael Elkins * main.c: set default MaxSize to 0 (unlimited) invert test for password being set after getpass() call (Magnus Jonsson ) 2000-12-22 07:14 Michael Elkins * configure.in, imap.c, isync.1, isync.h, isyncrc.sample, maildir.c, main.c, sync.c: added MaxSize configuration variable fixed --fast to work robustly without relying on the \Recent flag in messages 2000-12-21 23:10 Michael Elkins * imap.c, isync.h, maildir.c, sync.c: RFC822.PEEK is obsolete in RFC2060. Use BODY.PEEK[] instead, which does the same thing keep track of the uidvalidity so isync can detect if the mailbox on the server has changed since the last sync. 2000-12-21 20:56 Michael Elkins * Makefile.am, isync.spec.in: added support for building RPMS 2000-12-21 19:49 Michael Elkins * Makefile.am, isync.1: added target for creating html version of the man page documented the imaps: prefix to the Host command 2000-12-21 19:11 Michael Elkins * imap.c, sync.c: can't assume flag order when fetching a message. just search for the first `{' to find the message size. 2000-12-21 18:16 Michael Elkins * isync.1, sync.c: added BUGS section to manpage detailing the fact that we break the maildir(5) spec by parsing the filename change message delivery to use the method described in maildir(5) 2000-12-21 17:51 Michael Elkins * configure.in, main.c, sync.c: use getpass() to get the user's password unlink the temp file if we are unable to fetch a new message from the server. update version to 0.3 2000-12-21 11:14 Michael Elkins * isync.1: fixed typo in man page for --verbose option 2000-12-21 10:24 Michael Elkins * Makefile.am, README, imap.c, isync.h, list.c: added generic IMAP list parser and rewrote imap_exec() to handle arbitrary data instead of hardcoded 2000-12-21 06:51 Michael Elkins * Makefile.am, README, configure.in, main.c: fixes to compile cleanly under Solaris 2.7 2000-12-21 06:27 Michael Elkins * configure.in, imap.c, isync.1, isync.h, main.c: added OpenSSL support 2000-12-21 00:35 Michael Elkins * configure.in, main.c: config options were not case insensitive 2000-12-21 00:30 Michael Elkins * imap.c, isync.h, maildir.c, main.c, sync.c: don't fetch deleted messages when expunging display number of messages that are to be deleted flags for \Recent messages were not properly fetched local messages with updated flags were not corrected renamed 2000-12-20 22:28 Michael Elkins * Makefile.am: updated ChangeLog added log: rule in Makefile.am 2000-12-20 22:10 Michael Elkins * autogen.sh: added autogen.sh to regenerate the build environment 2000-12-20 22:00 Michael Elkins * COPYING: added missing files 2000-12-20 21:41 Michael Elkins * AUTHORS, Makefile.am, README, configure.in, imap.c, isync.1, isync.h, isyncrc.sample, maildir.c, main.c, sync.c: initial import isync-1.4.4/depcomp0000755000175000001440000005602014006611564011145 00000000000000#! /bin/sh # depcomp - compile a program generating dependencies as side-effects scriptversion=2018-03-07.03; # UTC # Copyright (C) 1999-2020 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Alexandre Oliva . case $1 in '') echo "$0: No command. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: depcomp [--help] [--version] PROGRAM [ARGS] Run PROGRAMS ARGS to compile a file, generating dependencies as side-effects. Environment variables: depmode Dependency tracking mode. source Source file read by 'PROGRAMS ARGS'. object Object file output by 'PROGRAMS ARGS'. DEPDIR directory where to store dependencies. depfile Dependency file to output. tmpdepfile Temporary file to use when outputting dependencies. libtool Whether libtool is used (yes/no). Report bugs to . EOF exit $? ;; -v | --v*) echo "depcomp $scriptversion" exit $? ;; esac # Get the directory component of the given path, and save it in the # global variables '$dir'. Note that this directory component will # be either empty or ending with a '/' character. This is deliberate. set_dir_from () { case $1 in */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;; *) dir=;; esac } # Get the suffix-stripped basename of the given path, and save it the # global variable '$base'. set_base_from () { base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'` } # If no dependency file was actually created by the compiler invocation, # we still have to create a dummy depfile, to avoid errors with the # Makefile "include basename.Plo" scheme. make_dummy_depfile () { echo "#dummy" > "$depfile" } # Factor out some common post-processing of the generated depfile. # Requires the auxiliary global variable '$tmpdepfile' to be set. aix_post_process_depfile () { # If the compiler actually managed to produce a dependency file, # post-process it. if test -f "$tmpdepfile"; then # Each line is of the form 'foo.o: dependency.h'. # Do two passes, one to just change these to # $object: dependency.h # and one to simply output # dependency.h: # which is needed to avoid the deleted-header problem. { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile" sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile" } > "$depfile" rm -f "$tmpdepfile" else make_dummy_depfile fi } # A tabulation character. tab=' ' # A newline character. nl=' ' # Character ranges might be problematic outside the C locale. # These definitions help. upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ lower=abcdefghijklmnopqrstuvwxyz digits=0123456789 alpha=${upper}${lower} if test -z "$depmode" || test -z "$source" || test -z "$object"; then echo "depcomp: Variables source, object and depmode must be set" 1>&2 exit 1 fi # Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. depfile=${depfile-`echo "$object" | sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} rm -f "$tmpdepfile" # Avoid interferences from the environment. gccflag= dashmflag= # Some modes work just like other modes, but use different flags. We # parameterize here, but still list the modes in the big case below, # to make depend.m4 easier to write. Note that we *cannot* use a case # here, because this file can only contain one case statement. if test "$depmode" = hp; then # HP compiler uses -M and no extra arg. gccflag=-M depmode=gcc fi if test "$depmode" = dashXmstdout; then # This is just like dashmstdout with a different argument. dashmflag=-xM depmode=dashmstdout fi cygpath_u="cygpath -u -f -" if test "$depmode" = msvcmsys; then # This is just like msvisualcpp but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvisualcpp fi if test "$depmode" = msvc7msys; then # This is just like msvc7 but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvc7 fi if test "$depmode" = xlc; then # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information. gccflag=-qmakedep=gcc,-MF depmode=gcc fi case "$depmode" in gcc3) ## gcc 3 implements dependency tracking that does exactly what ## we want. Yay! Note: for some reason libtool 1.4 doesn't like ## it if -MD -MP comes after the -MF stuff. Hmm. ## Unfortunately, FreeBSD c89 acceptance of flags depends upon ## the command line argument order; so add the flags where they ## appear in depend2.am. Note that the slowdown incurred here ## affects only configure: in makefiles, %FASTDEP% shortcuts this. for arg do case $arg in -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; *) set fnord "$@" "$arg" ;; esac shift # fnord shift # $arg done "$@" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi mv "$tmpdepfile" "$depfile" ;; gcc) ## Note that this doesn't just cater to obsosete pre-3.x GCC compilers. ## but also to in-use compilers like IMB xlc/xlC and the HP C compiler. ## (see the conditional assignment to $gccflag above). ## There are various ways to get dependency output from gcc. Here's ## why we pick this rather obscure method: ## - Don't want to use -MD because we'd like the dependencies to end ## up in a subdir. Having to rename by hand is ugly. ## (We might end up doing this anyway to support other compilers.) ## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like ## -MM, not -M (despite what the docs say). Also, it might not be ## supported by the other compilers which use the 'gcc' depmode. ## - Using -M directly means running the compiler twice (even worse ## than renaming). if test -z "$gccflag"; then gccflag=-MD, fi "$@" -Wp,"$gccflag$tmpdepfile" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The second -e expression handles DOS-style file names with drive # letters. sed -e 's/^[^:]*: / /' \ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" ## This next piece of magic avoids the "deleted header file" problem. ## The problem is that when a header file which appears in a .P file ## is deleted, the dependency causes make to die (because there is ## typically no way to rebuild the header). We avoid this by adding ## dummy dependencies for each header file. Too bad gcc doesn't do ## this for us directly. ## Some versions of gcc put a space before the ':'. On the theory ## that the space means something, we add a space to the output as ## well. hp depmode also adds that space, but also prefixes the VPATH ## to the object. Take care to not repeat it in the output. ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; sgi) if test "$libtool" = yes; then "$@" "-Wp,-MDupdate,$tmpdepfile" else "$@" -MDupdate "$tmpdepfile" fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files echo "$object : \\" > "$depfile" # Clip off the initial element (the dependent). Don't try to be # clever and replace this with sed code, as IRIX sed won't handle # lines with more than a fixed number of characters (4096 in # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; # the IRIX cc adds comments like '#:fec' to the end of the # dependency line. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \ | tr "$nl" ' ' >> "$depfile" echo >> "$depfile" # The second pass generates a dummy entry for each header file. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ >> "$depfile" else make_dummy_depfile fi rm -f "$tmpdepfile" ;; xlc) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; aix) # The C for AIX Compiler uses -M and outputs the dependencies # in a .u file. In older versions, this file always lives in the # current directory. Also, the AIX compiler puts '$object:' at the # start of each line; $object doesn't have directory information. # Version 6 uses the directory in both cases. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then tmpdepfile1=$dir$base.u tmpdepfile2=$base.u tmpdepfile3=$dir.libs/$base.u "$@" -Wc,-M else tmpdepfile1=$dir$base.u tmpdepfile2=$dir$base.u tmpdepfile3=$dir$base.u "$@" -M fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done aix_post_process_depfile ;; tcc) # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26 # FIXME: That version still under development at the moment of writing. # Make that this statement remains true also for stable, released # versions. # It will wrap lines (doesn't matter whether long or short) with a # trailing '\', as in: # # foo.o : \ # foo.c \ # foo.h \ # # It will put a trailing '\' even on the last line, and will use leading # spaces rather than leading tabs (at least since its commit 0394caf7 # "Emit spaces for -MD"). "$@" -MD -MF "$tmpdepfile" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'. # We have to change lines of the first kind to '$object: \'. sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile" # And for each line of the second kind, we have to emit a 'dep.h:' # dummy dependency, to avoid the deleted-header problem. sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile" rm -f "$tmpdepfile" ;; ## The order of this option in the case statement is important, since the ## shell code in configure will try each of these formats in the order ## listed in this file. A plain '-MD' option would be understood by many ## compilers, so we must ensure this comes after the gcc and icc options. pgcc) # Portland's C compiler understands '-MD'. # Will always output deps to 'file.d' where file is the root name of the # source file under compilation, even if file resides in a subdirectory. # The object file name does not affect the name of the '.d' file. # pgcc 10.2 will output # foo.o: sub/foo.c sub/foo.h # and will wrap long lines using '\' : # foo.o: sub/foo.c ... \ # sub/foo.h ... \ # ... set_dir_from "$object" # Use the source, not the object, to determine the base name, since # that's sadly what pgcc will do too. set_base_from "$source" tmpdepfile=$base.d # For projects that build the same source file twice into different object # files, the pgcc approach of using the *source* file root name can cause # problems in parallel builds. Use a locking strategy to avoid stomping on # the same $tmpdepfile. lockdir=$base.d-lock trap " echo '$0: caught signal, cleaning up...' >&2 rmdir '$lockdir' exit 1 " 1 2 13 15 numtries=100 i=$numtries while test $i -gt 0; do # mkdir is a portable test-and-set. if mkdir "$lockdir" 2>/dev/null; then # This process acquired the lock. "$@" -MD stat=$? # Release the lock. rmdir "$lockdir" break else # If the lock is being held by a different process, wait # until the winning process is done or we timeout. while test -d "$lockdir" && test $i -gt 0; do sleep 1 i=`expr $i - 1` done fi i=`expr $i - 1` done trap - 1 2 13 15 if test $i -le 0; then echo "$0: failed to acquire lock after $numtries attempts" >&2 echo "$0: check lockdir '$lockdir'" >&2 exit 1 fi if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each line is of the form `foo.o: dependent.h', # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. # Do two passes, one to just change these to # `$object: dependent.h' and one to simply `dependent.h:'. sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this invocation # correctly. Breaking it into two sed invocations is a workaround. sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp2) # The "hp" stanza above does not work with aCC (C++) and HP's ia64 # compilers, which have integrated preprocessors. The correct option # to use with these is +Maked; it writes dependencies to a file named # 'foo.d', which lands next to the object file, wherever that # happens to be. # Much of this is similar to the tru64 case; see comments there. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then tmpdepfile1=$dir$base.d tmpdepfile2=$dir.libs/$base.d "$@" -Wc,+Maked else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d "$@" +Maked fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile" # Add 'dependent.h:' lines. sed -ne '2,${ s/^ *// s/ \\*$// s/$/:/ p }' "$tmpdepfile" >> "$depfile" else make_dummy_depfile fi rm -f "$tmpdepfile" "$tmpdepfile2" ;; tru64) # The Tru64 compiler uses -MD to generate dependencies as a side # effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'. # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put # dependencies in 'foo.d' instead, so we check for that too. # Subdirectories are respected. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then # Libtool generates 2 separate objects for the 2 libraries. These # two compilations output dependencies in $dir.libs/$base.o.d and # in $dir$base.o.d. We have to check for both files, because # one of the two compilations can be disabled. We should prefer # $dir$base.o.d over $dir.libs/$base.o.d because the latter is # automatically cleaned when .libs/ is deleted, while ignoring # the former would cause a distcleancheck panic. tmpdepfile1=$dir$base.o.d # libtool 1.5 tmpdepfile2=$dir.libs/$base.o.d # Likewise. tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504 "$@" -Wc,-MD else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d tmpdepfile3=$dir$base.d "$@" -MD fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done # Same post-processing that is required for AIX mode. aix_post_process_depfile ;; msvc7) if test "$libtool" = yes; then showIncludes=-Wc,-showIncludes else showIncludes=-showIncludes fi "$@" $showIncludes > "$tmpdepfile" stat=$? grep -v '^Note: including file: ' "$tmpdepfile" if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The first sed program below extracts the file names and escapes # backslashes for cygpath. The second sed program outputs the file # name when reading, but also accumulates all include files in the # hold buffer in order to output them again at the end. This only # works with sed implementations that can handle large buffers. sed < "$tmpdepfile" -n ' /^Note: including file: *\(.*\)/ { s//\1/ s/\\/\\\\/g p }' | $cygpath_u | sort -u | sed -n ' s/ /\\ /g s/\(.*\)/'"$tab"'\1 \\/p s/.\(.*\) \\/\1:/ H $ { s/.*/'"$tab"'/ G p }' >> "$depfile" echo >> "$depfile" # make sure the fragment doesn't end with a backslash rm -f "$tmpdepfile" ;; msvc7msys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; #nosideeffect) # This comment above is used by automake to tell side-effect # dependency tracking mechanisms from slower ones. dashmstdout) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout, regardless of -o. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done test -z "$dashmflag" && dashmflag=-M # Require at least two characters before searching for ':' # in the target name. This is to cope with DOS-style filenames: # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise. "$@" $dashmflag | sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile" rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this sed invocation # correctly. Breaking it into two sed invocations is a workaround. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; dashXmstdout) # This case only exists to satisfy depend.m4. It is never actually # run, as this mode is specially recognized in the preamble. exit 1 ;; makedepend) "$@" || exit $? # Remove any Libtool call if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # X makedepend shift cleared=no eat=no for arg do case $cleared in no) set ""; shift cleared=yes ;; esac if test $eat = yes; then eat=no continue fi case "$arg" in -D*|-I*) set fnord "$@" "$arg"; shift ;; # Strip any option that makedepend may not understand. Remove # the object too, otherwise makedepend will parse it as a source file. -arch) eat=yes ;; -*|$object) ;; *) set fnord "$@" "$arg"; shift ;; esac done obj_suffix=`echo "$object" | sed 's/^.*\././'` touch "$tmpdepfile" ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" rm -f "$depfile" # makedepend may prepend the VPATH from the source file name to the object. # No need to regex-escape $object, excess matching of '.' is harmless. sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process the last invocation # correctly. Breaking it into two sed invocations is a workaround. sed '1,2d' "$tmpdepfile" \ | tr ' ' "$nl" \ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" "$tmpdepfile".bak ;; cpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done "$@" -E \ | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ | sed '$ s: \\$::' > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" cat < "$tmpdepfile" >> "$depfile" sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; msvisualcpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi IFS=" " for arg do case "$arg" in -o) shift ;; $object) shift ;; "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") set fnord "$@" shift shift ;; *) set fnord "$@" "$arg" shift shift ;; esac done "$@" -E 2>/dev/null | sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile" echo "$tab" >> "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" rm -f "$tmpdepfile" ;; msvcmsys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; none) exec "$@" ;; *) echo "Unknown depmode $depmode" 1>&2 exit 1 ;; esac exit 0 # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: isync-1.4.4/TODO0000644000175000001440000000710014006611550010246 00000000000000f{,data}sync() usage could be optimized by batching the calls. make SSL (connect) timeouts produce a bit more than "Unidentified socket error". automatically resume upon transient errors, e.g. "connection reset by peer" or timeout after some data was already transmitted. possibly also try to handle Exchange's "glitches" somehow. add support for IMAP UTF-7 (for internationalized mailbox names). uidvalidity lock timeout handling would be a good idea. should complain when multiple Channels match the same folders. propagate folder deletions even when the folders are non-empty. - verify that "most" of the folders in the Channel are still there. - refuse to delete unpropagated messages when trashing on the remote side. - refuse to delete far side if it has unpropagated messages. symmetry? add message expiration based on arrival date (message date would be too unreliable). MaxAge; probably mutually exclusive to MaxMessages. add alternative treatments of expired messages. ExpiredMessageMode: Prune (delete messages like now), Keep (just don't sync) and Archive (move to separate folder - ArchiveSuffix, default .archive). add support for event notification callbacks. it would be also possible to report more differentiated exit codes, but that seems too limiting in the general case. make it possible to have different mailbox names for far and near side in Patterns. - use far:near for the pattern - for quoting, use more colons: the longest sequence of colons is the separator - this makes Groups mostly useless, as they are mostly a workaround for this function being missing so far - this is needed for move detection, which would work only within one Channel add regexp-based mailbox path rewriting to the drivers. user would provide expressions for both directions. every transformation would be immediately verified with the inverse transform. PathDelimiter and Flatten would become special cases of this. add daemon mode. primary goal: keep imap password in memory. also: idling mode. parallel fetching of multiple mailboxes. TLS session resumption becomes interesting then as well. imap_set_flags(): group commands for efficiency, don't call back until imap_commit(). add streaming from fetching to storing. handle custom flags (keywords). make use of IMAP CONDSTORE extension (rfc4551; CHANGEDSINCE FETCH Modifier); make use of IMAP QRESYNC extension (rfc5162) to avoid SEARCH to find vanished messages. use MULTIAPPEND and FETCH with multiple messages. dummy messages resulting from MaxSize should contain a dump of the original message's MIME structure and its (reasonably sized) text parts. don't SELECT boxes unless really needed; in particular not for appending, and in write-only mode not before changes are made. problem: UIDVALIDITY change detection is delayed, significantly complicating matters. some error messages are unhelpful in non-verbose mode due to missing context. possibly use ^[[1m to highlight error messages. consider alternative approach to trashing: instead of the current trash-before- expunge done by mbsync, let MUAs do the trashing (as modern ones typically do). mbsync wouldn't do any trashing by itself, but should track the moves for optimization. additionally, there should be a mode to move trashed messages to the remote store. TrashMode Internal|External, AbsorbRemoteTrash. a yet different approach to trashing is treating the trash like a normal mailbox. however, this implies a huge working set. consider optional use of messages-id (and X-GM-MSGID): - detection of message moves between folders - recovery from loss of sync state, migration from other tools isync-1.4.4/NEWS0000644000175000001440000001303114006611550010255 00000000000000[1.4.0] The 'isync' compatibility wrapper was removed. Added support for disabling TLS v1.3 - adjust SSLVersions if you set it. Removed support for obsolete/insecure SSL v3. The IMAP '$Forwarded' / Maildir 'P' (passed) flag is supported now. Support for configuring a TLS cipher string was added. IMAP mailbox subscriptions are supported now. The IMAP user query can be scripted now. Added built-in support for macOS Keychain. Messages excluded by MaxSize will now result in placeholders. The use of Master/Slave terminology has been deprecated. [1.3.0] Network timeout handling has been added. Support for proper Maildir++ and a Maildir sub-folder naming style without extra dots have been added. Support for TLS client certificates was added. Support for recovering from baseless UID validity changes was added. The get-cert script was renamed to mbsync-get-cert. [1.2.0] The 'isync' compatibility wrapper is now deprecated. An IMAP Path/NAMESPACE rooted in INBOX won't be handled specially any more. This means that some Patterns may need adjustment. The default output is a lot less verbose now. The meanings of the -V and -D options changed significantly. The SSL/TLS configuration has been re-designed. SSL is now explicitly enabled or disabled - "use SSL if available" is gone. Notice: Tunnels are assumed to be secure and thus default to no SSL. Support for SASL (flexible authentication) has been added. Support for Windows file systems has been added. Support for compressed data transfer has been added. Folder deletions can be propagated now. [1.1.0] Support for hierarchical mailboxes in Patterns. Full support for IMAP pipelining (streaming, parallelization) added. This is considerably faster especially with high-latency networks. Faster and hopefully more reliable support for IMAP servers without the UIDPLUS extension (e.g., M$ Exchange). More automatic handling of SSL certificates. IPv6 support. IMAP password query can be scripted. Message arrival dates can be propagated. Data safety in case of system crashes was improved. MaxMessages was made vastly more useful. [1.0.0] Essentially a rewrite. Synchronization state storage concept, configuration and command line changed entirely. But you needn't to worry about the upgrade, as a fully automated migration path is provided, even for users of isync 0.7 and below. Still, you should re-read the manual to be able to take full advantage of the new features: The supported mailbox types can be freely paired. A possible application of this is using a local IMAP server to access mailboxes that are not natively supported yet. Message deletions (expunges) are now propagated both ways, so there is no need for using mutt with maildir_trash any more. Additional trash options added. `OneToOne' replaced by something more flexible. Partial support for IMAP pipelining (streaming, parallelization) added. Makes flag change propagation much faster - this affects every message that becomes Seen/Read. [0.9] Added Tunnel directive to allow the user to specify a shell command to run to set up an IMAP connection in place of a TCP socket (eg., to run over an SSH session). Added PREAUTH support (useful mostly in conjunction with Tunnel). Messages marked deleted are not uploaded when we are going to expunge. Locally generated messages are not re-fetched after uploading even if the UIDPLUS extension is not supported by the server. Added `OneToOne' configuration option: ignore any Mailbox specifications and instead pick up all mailboxes from the local MailDir and remote Folder and map them 1:1 onto each other according to their names. -C now creates both local and remote boxes; -L and -R create only local/remote. --quiet is now really quiet. [0.8] !!! IMPORTANT !!! In order to fix the problem where messages copied from one mailbox to another were not uploaded to the new mailbox, the way Isync stores the UID for each message needed to be changed. As a result, you _MUST_ delete all the messages in the local maildir box before using this version. Otherwise it will upload every message to the server thinking its a new mail. [0.7] Added `MaxMessages' configuration option to allow tracking of only the most recently added message in the local mailbox. Added --create (-C) command line option to force creation of the local maildir-style mailbox if it doesn't already exist. [0.6] Added `Delete' configuration option to correspond to the -d command line option. Added -a (--all) command line option to synchronize all mailboxes. [0.5] Updated SSL support. Added CRAM authentication support. Added MailDir configuration option to specify the default location of local mailboxes when relative paths are used. Added support for uploading local messages to the IMAP server. Added CopyDeletedTo configuration option to cause isync to move deleted messages to a particular mailbox on the server when they are expunged. [0.4] Added MaxSize configuration option to limit downloading of new messages from the server to less than some threshold. More robust --fast option works without using \Recent flags, so the previous problem with multiple accesses killing these flags is no longer a problem. RFC2060 obsoleted RFC822.PEEK, use BODY.PEEK[] instead which does the same job. Don't need to request UID in a FETCH when doing UID FETCH (RFC2060 states that its automatically returned). [0.3] Fixed to clean up temp maildir files when the fetch of a new message failed. Fixed to not assume order of the flags returned by "UID FETCH" Added support for building RPMs. [0.2] SSL support added. [0.1] Initial release. isync-1.4.4/isync.spec.in0000644000175000001440000000162614006611550012173 00000000000000Summary: Utility to synchronize IMAP mailboxes with local maildir folders Name: isync Version: @VERSION@ Release: 1 License: GPL Group: Applications/Internet Source: @PACKAGE@-@VERSION@.tar.gz URL: http://@PACKAGE@.sf.net/ Packager: Oswald Buddenhagen BuildRoot: /var/tmp/%{name}-buildroot %description isync is a command line utility which synchronizes mailboxes; currently Maildir and IMAP4 mailboxes are supported. New messages, message deletions and flag changes can be propagated both ways. It is useful for working in disconnected mode, such as on a laptop or with a non-permanent internet collection (dIMAP). %prep %setup %build %configure %install rm -rf $RPM_BUILD_ROOT make DESTDIR=$RPM_BUILD_ROOT install rm -rf $RPM_BUILD_ROOT%{_docdir}/%{name} %clean rm -rf $RPM_BUILD_ROOT %files %doc AUTHORS COPYING NEWS README TODO ChangeLog src/mbsyncrc.sample %{_bindir}/* %{_mandir}/man1/* isync-1.4.4/compile0000755000175000001440000001635014006611564011150 00000000000000#! /bin/sh # Wrapper for compilers which do not understand '-c -o'. scriptversion=2018-03-07.03; # UTC # Copyright (C) 1999-2020 Free Software Foundation, Inc. # Written by Tom Tromey . # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # This file is maintained in Automake, please report # bugs to or send patches to # . nl=' ' # We need space, tab and new line, in precisely that order. Quoting is # there to prevent tools from complaining about whitespace usage. IFS=" "" $nl" file_conv= # func_file_conv build_file lazy # Convert a $build file to $host form and store it in $file # Currently only supports Windows hosts. If the determined conversion # type is listed in (the comma separated) LAZY, no conversion will # take place. func_file_conv () { file=$1 case $file in / | /[!/]*) # absolute file, and not a UNC file if test -z "$file_conv"; then # lazily determine how to convert abs files case `uname -s` in MINGW*) file_conv=mingw ;; CYGWIN* | MSYS*) file_conv=cygwin ;; *) file_conv=wine ;; esac fi case $file_conv/,$2, in *,$file_conv,*) ;; mingw/*) file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` ;; cygwin/* | msys/*) file=`cygpath -m "$file" || echo "$file"` ;; wine/*) file=`winepath -w "$file" || echo "$file"` ;; esac ;; esac } # func_cl_dashL linkdir # Make cl look for libraries in LINKDIR func_cl_dashL () { func_file_conv "$1" if test -z "$lib_path"; then lib_path=$file else lib_path="$lib_path;$file" fi linker_opts="$linker_opts -LIBPATH:$file" } # func_cl_dashl library # Do a library search-path lookup for cl func_cl_dashl () { lib=$1 found=no save_IFS=$IFS IFS=';' for dir in $lib_path $LIB do IFS=$save_IFS if $shared && test -f "$dir/$lib.dll.lib"; then found=yes lib=$dir/$lib.dll.lib break fi if test -f "$dir/$lib.lib"; then found=yes lib=$dir/$lib.lib break fi if test -f "$dir/lib$lib.a"; then found=yes lib=$dir/lib$lib.a break fi done IFS=$save_IFS if test "$found" != yes; then lib=$lib.lib fi } # func_cl_wrapper cl arg... # Adjust compile command to suit cl func_cl_wrapper () { # Assume a capable shell lib_path= shared=: linker_opts= for arg do if test -n "$eat"; then eat= else case $1 in -o) # configure might choose to run compile as 'compile cc -o foo foo.c'. eat=1 case $2 in *.o | *.[oO][bB][jJ]) func_file_conv "$2" set x "$@" -Fo"$file" shift ;; *) func_file_conv "$2" set x "$@" -Fe"$file" shift ;; esac ;; -I) eat=1 func_file_conv "$2" mingw set x "$@" -I"$file" shift ;; -I*) func_file_conv "${1#-I}" mingw set x "$@" -I"$file" shift ;; -l) eat=1 func_cl_dashl "$2" set x "$@" "$lib" shift ;; -l*) func_cl_dashl "${1#-l}" set x "$@" "$lib" shift ;; -L) eat=1 func_cl_dashL "$2" ;; -L*) func_cl_dashL "${1#-L}" ;; -static) shared=false ;; -Wl,*) arg=${1#-Wl,} save_ifs="$IFS"; IFS=',' for flag in $arg; do IFS="$save_ifs" linker_opts="$linker_opts $flag" done IFS="$save_ifs" ;; -Xlinker) eat=1 linker_opts="$linker_opts $2" ;; -*) set x "$@" "$1" shift ;; *.cc | *.CC | *.cxx | *.CXX | *.[cC]++) func_file_conv "$1" set x "$@" -Tp"$file" shift ;; *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO]) func_file_conv "$1" mingw set x "$@" "$file" shift ;; *) set x "$@" "$1" shift ;; esac fi shift done if test -n "$linker_opts"; then linker_opts="-link$linker_opts" fi exec "$@" $linker_opts exit 1 } eat= case $1 in '') echo "$0: No command. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: compile [--help] [--version] PROGRAM [ARGS] Wrapper for compilers which do not understand '-c -o'. Remove '-o dest.o' from ARGS, run PROGRAM with the remaining arguments, and rename the output as expected. If you are trying to build a whole package this is not the right script to run: please start by reading the file 'INSTALL'. Report bugs to . EOF exit $? ;; -v | --v*) echo "compile $scriptversion" exit $? ;; cl | *[/\\]cl | cl.exe | *[/\\]cl.exe | \ icl | *[/\\]icl | icl.exe | *[/\\]icl.exe ) func_cl_wrapper "$@" # Doesn't return... ;; esac ofile= cfile= for arg do if test -n "$eat"; then eat= else case $1 in -o) # configure might choose to run compile as 'compile cc -o foo foo.c'. # So we strip '-o arg' only if arg is an object. eat=1 case $2 in *.o | *.obj) ofile=$2 ;; *) set x "$@" -o "$2" shift ;; esac ;; *.c) cfile=$1 set x "$@" "$1" shift ;; *) set x "$@" "$1" shift ;; esac fi shift done if test -z "$ofile" || test -z "$cfile"; then # If no '-o' option was seen then we might have been invoked from a # pattern rule where we don't need one. That is ok -- this is a # normal compilation that the losing compiler can handle. If no # '.c' file was seen then we are probably linking. That is also # ok. exec "$@" fi # Name of file we expect compiler to create. cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` # Create the lock directory. # Note: use '[/\\:.-]' here to ensure that we don't use the same name # that we are using for the .o file. Also, base the name on the expected # object file name, since that is what matters with a parallel build. lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d while true; do if mkdir "$lockdir" >/dev/null 2>&1; then break fi sleep 1 done # FIXME: race condition here if user kills between mkdir and trap. trap "rmdir '$lockdir'; exit 1" 1 2 15 # Run the compile. "$@" ret=$? if test -f "$cofile"; then test "$cofile" = "$ofile" || mv "$cofile" "$ofile" elif test -f "${cofile}bj"; then test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" fi rmdir "$lockdir" exit $ret # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: isync-1.4.4/isync.spec0000644000175000001440000000160614152373731011574 00000000000000Summary: Utility to synchronize IMAP mailboxes with local maildir folders Name: isync Version: 1.4.4 Release: 1 License: GPL Group: Applications/Internet Source: isync-1.4.4.tar.gz URL: http://isync.sf.net/ Packager: Oswald Buddenhagen BuildRoot: /var/tmp/%{name}-buildroot %description isync is a command line utility which synchronizes mailboxes; currently Maildir and IMAP4 mailboxes are supported. New messages, message deletions and flag changes can be propagated both ways. It is useful for working in disconnected mode, such as on a laptop or with a non-permanent internet collection (dIMAP). %prep %setup %build %configure %install rm -rf $RPM_BUILD_ROOT make DESTDIR=$RPM_BUILD_ROOT install rm -rf $RPM_BUILD_ROOT%{_docdir}/%{name} %clean rm -rf $RPM_BUILD_ROOT %files %doc AUTHORS COPYING NEWS README TODO ChangeLog src/mbsyncrc.sample %{_bindir}/* %{_mandir}/man1/* isync-1.4.4/install-sh0000755000175000001440000003577614006611564011613 00000000000000#!/bin/sh # install - install a program, script, or datafile scriptversion=2020-11-14.01; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # 'make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. tab=' ' nl=' ' IFS=" $tab$nl" # Set DOITPROG to "echo" to test this script. doit=${DOITPROG-} doit_exec=${doit:-exec} # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_mkdir= # Desired mode of installed file. mode=0755 # Create dirs (including intermediate dirs) using mode 755. # This is like GNU 'install' as of coreutils 8.32 (2020). mkdir_umask=22 backupsuffix= chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false is_target_a_directory=possibly usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -p pass -p to $cpprog. -s $stripprog installed files. -S SUFFIX attempt to back up existing files, with suffix SUFFIX. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG By default, rm is invoked with -f; when overridden with RMPROG, it's up to you to specify -f if you want it. If -S is not specified, no backups are attempted. Email bug reports to bug-automake@gnu.org. Automake home page: https://www.gnu.org/software/automake/ " while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -p) cpprog="$cpprog -p";; -s) stripcmd=$stripprog;; -S) backupsuffix="$2" shift;; -t) is_target_a_directory=always dst_arg=$2 # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac shift;; -T) is_target_a_directory=never;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done # We allow the use of options -d and -T together, by making -d # take the precedence; this is for compatibility with GNU install. if test -n "$dir_arg"; then if test -n "$dst_arg"; then echo "$0: target directory not allowed when installing a directory." >&2 exit 1 fi fi if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call 'install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then if test $# -gt 1 || test "$is_target_a_directory" = always; then if test ! -d "$dst_arg"; then echo "$0: $dst_arg: Is not a directory." >&2 exit 1 fi fi fi if test -z "$dir_arg"; then do_exit='(exit $ret); exit $ret' trap "ret=129; $do_exit" 1 trap "ret=130; $do_exit" 2 trap "ret=141; $do_exit" 13 trap "ret=143; $do_exit" 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names problematic for 'test' and other utilities. case $src in -* | [=\(\)!]) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? # Don't chown directories that already exist. if test $dstdir_status = 0; then chowncmd="" fi else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # If destination is a directory, append the input filename. if test -d "$dst"; then if test "$is_target_a_directory" = never; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dstbase=`basename "$src"` case $dst in */) dst=$dst$dstbase;; *) dst=$dst/$dstbase;; esac dstdir_status=0 else dstdir=`dirname "$dst"` test -d "$dstdir" dstdir_status=$? fi fi case $dstdir in */) dstdirslash=$dstdir;; *) dstdirslash=$dstdir/;; esac obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false # The $RANDOM variable is not portable (e.g., dash). Use it # here however when possible just to lower collision chance. tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap ' ret=$? rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null exit $ret ' 0 # Because "mkdir -p" follows existing symlinks and we likely work # directly in world-writeable /tmp, make sure that the '$tmpdir' # directory is successfully created first before we actually test # 'mkdir -p'. if (umask $mkdir_umask && $mkdirprog $mkdir_mode "$tmpdir" && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. test_tmpdir="$tmpdir/a" ls_ld_tmpdir=`ls -ld "$test_tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$test_tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null fi trap '' 0;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; [-=\(\)!]*) prefix='./';; *) prefix='';; esac oIFS=$IFS IFS=/ set -f set fnord $dstdir shift set +f IFS=$oIFS prefixes= for d do test X"$d" = X && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=${dstdirslash}_inst.$$_ rmtmp=${dstdirslash}_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && { test -z "$stripcmd" || { # Create $dsttmp read-write so that cp doesn't create it read-only, # which would cause strip to fail. if test -z "$doit"; then : >"$dsttmp" # No need to fork-exec 'touch'. else $doit touch "$dsttmp" fi } } && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # If $backupsuffix is set, and the file being installed # already exists, attempt a backup. Don't worry if it fails, # e.g., if mv doesn't support -f. if test -n "$backupsuffix" && test -f "$dst"; then $doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null fi # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: isync-1.4.4/config.sub0000755000175000001440000010645014006611564011556 00000000000000#! /bin/sh # Configuration validation subroutine script. # Copyright 1992-2018 Free Software Foundation, Inc. timestamp='2018-02-22' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # Please send patches to . # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: # https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS Canonicalize a configuration name. Options: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright 1992-2018 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo "$1" exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo "$1" | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \ kopensolaris*-gnu* | cloudabi*-eabi* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo "$1" | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; android-linux) os=-linux-android basic_machine=`echo "$1" | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown ;; *) basic_machine=`echo "$1" | sed 's/-[^-]*$//'` if [ "$basic_machine" != "$1" ] then os=`echo "$1" | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis | -knuth | -cray | -microblaze*) os= basic_machine=$1 ;; -bluegene*) os=-cnk ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco6) os=-sco5v6 basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` ;; -sco5) os=-sco3.2v5 basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` ;; -sco5v6*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'` ;; -lynx*178) os=-lynxos178 ;; -lynx*5) os=-lynxos5 ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo "$1" | sed -e 's/86-.*/86-sequent/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | aarch64 | aarch64_be \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arceb \ | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ | avr | avr32 \ | ba \ | be32 | be64 \ | bfin \ | c4x | c8051 | clipper \ | d10v | d30v | dlx | dsp16xx \ | e2k | epiphany \ | fido | fr30 | frv | ft32 \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | hexagon \ | i370 | i860 | i960 | ia16 | ia64 \ | ip2k | iq2000 \ | k1om \ | le32 | le64 \ | lm32 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64octeon | mips64octeonel \ | mips64orion | mips64orionel \ | mips64r5900 | mips64r5900el \ | mips64vr | mips64vrel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa32r6 | mipsisa32r6el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64r6 | mipsisa64r6el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipsr5900 | mipsr5900el \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | moxie \ | mt \ | msp430 \ | nds32 | nds32le | nds32be \ | nios | nios2 | nios2eb | nios2el \ | ns16k | ns32k \ | open8 | or1k | or1knd | or32 \ | pdp10 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle \ | pru \ | pyramid \ | riscv32 | riscv64 \ | rl78 | rx \ | score \ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ | spu \ | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ | ubicom32 \ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ | visium \ | wasm32 \ | x86 | xc16x | xstormy16 | xtensa \ | z8k | z80) basic_machine=$basic_machine-unknown ;; c54x) basic_machine=tic54x-unknown ;; c55x) basic_machine=tic55x-unknown ;; c6x) basic_machine=tic6x-unknown ;; leon|leon[3-9]) basic_machine=sparc-$basic_machine ;; m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip) basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65) ;; ms1) basic_machine=mt-unknown ;; strongarm | thumb | xscale) basic_machine=arm-unknown ;; xgate) basic_machine=$basic_machine-unknown os=-none ;; xscaleeb) basic_machine=armeb-unknown ;; xscaleel) basic_machine=armel-unknown ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`"$1"\': machine \`"$basic_machine"\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | aarch64-* | aarch64_be-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ | ba-* \ | be32-* | be64-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* \ | c8051-* | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | e2k-* | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | hexagon-* \ | i*86-* | i860-* | i960-* | ia16-* | ia64-* \ | ip2k-* | iq2000-* \ | k1om-* \ | le32-* | le64-* \ | lm32-* \ | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ | microblaze-* | microblazeel-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64octeon-* | mips64octeonel-* \ | mips64orion-* | mips64orionel-* \ | mips64r5900-* | mips64r5900el-* \ | mips64vr-* | mips64vrel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mips64vr5900-* | mips64vr5900el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa32r6-* | mipsisa32r6el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64r6-* | mipsisa64r6el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipsr5900-* | mipsr5900el-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | mt-* \ | msp430-* \ | nds32-* | nds32le-* | nds32be-* \ | nios-* | nios2-* | nios2eb-* | nios2el-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | open8-* \ | or1k*-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ | pru-* \ | pyramid-* \ | riscv32-* | riscv64-* \ | rl78-* | romp-* | rs6000-* | rx-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \ | tahoe-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tile*-* \ | tron-* \ | ubicom32-* \ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ | vax-* \ | visium-* \ | wasm32-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* \ | xstormy16-* | xtensa*-* \ | ymp-* \ | z8k-* | z80-*) ;; # Recognize the basic CPU types without company name, with glob match. xtensa*) basic_machine=$basic_machine-unknown ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-pc os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; abacus) basic_machine=abacus-unknown ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amd64) basic_machine=x86_64-pc ;; amd64-*) basic_machine=x86_64-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aros) basic_machine=i386-pc os=-aros ;; asmjs) basic_machine=asmjs-unknown ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; blackfin) basic_machine=bfin-unknown os=-linux ;; blackfin-*) basic_machine=bfin-`echo "$basic_machine" | sed 's/^[^-]*-//'` os=-linux ;; bluegene*) basic_machine=powerpc-ibm os=-cnk ;; c54x-*) basic_machine=tic54x-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; c55x-*) basic_machine=tic55x-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; c6x-*) basic_machine=tic6x-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; c90) basic_machine=c90-cray os=-unicos ;; cegcc) basic_machine=arm-unknown os=-cegcc ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; craynv) basic_machine=craynv-cray os=-unicosmp ;; cr16 | cr16-*) basic_machine=cr16-unknown os=-elf ;; crds | unos) basic_machine=m68k-crds ;; crisv32 | crisv32-* | etraxfs*) basic_machine=crisv32-axis ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; crx) basic_machine=crx-unknown os=-elf ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dicos) basic_machine=i686-pc os=-dicos ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2*) basic_machine=m68k-bull os=-sysv3 ;; e500v[12]) basic_machine=powerpc-unknown os=$os"spe" ;; e500v[12]-*) basic_machine=powerpc-`echo "$basic_machine" | sed 's/^[^-]*-//'` os=$os"spe" ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; i*86v32) basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; leon-*|leon[3-9]-*) basic_machine=sparc-`echo "$basic_machine" | sed 's/-.*//'` ;; m68knommu) basic_machine=m68k-unknown os=-linux ;; m68knommu-*) basic_machine=m68k-`echo "$basic_machine" | sed 's/^[^-]*-//'` os=-linux ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; microblaze*) basic_machine=microblaze-xilinx ;; mingw64) basic_machine=x86_64-pc os=-mingw64 ;; mingw32) basic_machine=i686-pc os=-mingw32 ;; mingw32ce) basic_machine=arm-unknown os=-mingw32ce ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo "$basic_machine" | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo "$basic_machine" | sed -e 's/mips3/mips64/'`-unknown ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; moxiebox) basic_machine=moxie-unknown os=-moxiebox ;; msdos) basic_machine=i386-pc os=-msdos ;; ms1-*) basic_machine=`echo "$basic_machine" | sed -e 's/ms1-/mt-/'` ;; msys) basic_machine=i686-pc os=-msys ;; mvs) basic_machine=i370-ibm os=-mvs ;; nacl) basic_machine=le32-unknown os=-nacl ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; neo-tandem) basic_machine=neo-tandem ;; nse-tandem) basic_machine=nse-tandem ;; nsr-tandem) basic_machine=nsr-tandem ;; nsv-tandem) basic_machine=nsv-tandem ;; nsx-tandem) basic_machine=nsx-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; openrisc | openrisc-*) basic_machine=or32-unknown ;; os400) basic_machine=powerpc-ibm os=-os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; parisc) basic_machine=hppa-unknown os=-linux ;; parisc-*) basic_machine=hppa-`echo "$basic_machine" | sed 's/^[^-]*-//'` os=-linux ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pc98) basic_machine=i386-pc ;; pc98-*) basic_machine=i386-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc | ppcbe) basic_machine=powerpc-unknown ;; ppc-* | ppcbe-*) basic_machine=powerpc-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rdos | rdos64) basic_machine=x86_64-pc os=-rdos ;; rdos32) basic_machine=i386-pc os=-rdos ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sde) basic_machine=mipsisa32-sde os=-elf ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh5el) basic_machine=sh5le-unknown ;; simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; strongarm-* | thumb-*) basic_machine=arm-`echo "$basic_machine" | sed 's/^[^-]*-//'` ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tile*) basic_machine=$basic_machine-unknown os=-linux-gnu ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; tpf) basic_machine=s390x-ibm os=-tpf ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; x64) basic_machine=x86_64-pc ;; xbox) basic_machine=i686-pc os=-mingw32 ;; xps | xps100) basic_machine=xps100-honeywell ;; xscale-* | xscalee[bl]-*) basic_machine=`echo "$basic_machine" | sed 's/^xscale/arm/'` ;; ymp) basic_machine=ymp-cray os=-unicos ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; mmix) basic_machine=mmix-knuth ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`"$1"\': machine \`"$basic_machine"\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo "$basic_machine" | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo "$basic_machine" | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases that might get confused # with valid system types. # -solaris* is a basic system type, with this one exception. -auroraux) os=-auroraux ;; -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # es1800 is here to avoid being matched by es* (a different OS) -es1800*) os=-ose ;; # Now accept the basic system types. # The portable systems comes first. # Each alternative MUST end in a * to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ | -sym* | -kopensolaris* | -plan9* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* | -aros* | -cloudabi* | -sortix* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -knetbsd* | -mirbsd* | -netbsd* \ | -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* | -cegcc* | -glidix* \ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ | -linux-newlib* | -linux-musl* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \ | -onefs* | -tirtos* | -phoenix* | -fuchsia* | -redox* | -bme* \ | -midnightbsd*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -xray | -os68k* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo "$os" | sed -e 's|mac|macos|'` ;; -linux-dietlibc) os=-linux-dietlibc ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo "$os" | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo "$os" | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -os400*) os=-os400 ;; -wince*) os=-wince ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -syllable*) os=-syllable ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -tpf*) os=-tpf ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4*) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -zvmoe) os=-zvmoe ;; -dicos*) os=-dicos ;; -pikeos*) # Until real need of OS specific support for # particular features comes up, bare metal # configurations are quite functional. case $basic_machine in arm*) os=-eabi ;; *) os=-elf ;; esac ;; -nacl*) ;; -ios) ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`"$1"\': system \`"$os"\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in score-*) os=-elf ;; spu-*) os=-elf ;; *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; c8051-*) os=-elf ;; hexagon-*) os=-elf ;; tic54x-*) os=-coff ;; tic55x-*) os=-coff ;; tic6x-*) os=-coff ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 ;; m68*-cisco) os=-aout ;; mep-*) os=-elf ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; pru-*) os=-elf ;; *-be) os=-beos ;; *-ibm) os=-aix ;; *-knuth) os=-mmixware ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -cnk*|-aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -os400*) vendor=ibm ;; -ptx*) vendor=sequent ;; -tpf*) vendor=ibm ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo "$basic_machine" | sed "s/unknown/$vendor/"` ;; esac echo "$basic_machine$os" exit # Local variables: # eval: (add-hook 'write-file-functions 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: isync-1.4.4/aclocal.m40000644000175000001440000014655514152373730011447 00000000000000# generated automatically by aclocal 1.16.5 -*- Autoconf -*- # Copyright (C) 1996-2021 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_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.71],, [m4_warning([this file was generated for autoconf 2.71. 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'.])]) # pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- # serial 12 (pkg-config-0.29.2) dnl Copyright © 2004 Scott James Remnant . dnl Copyright © 2012-2015 Dan Nicholson dnl dnl This program is free software; you can redistribute it and/or modify dnl it under the terms of the GNU General Public License as published by dnl the Free Software Foundation; either version 2 of the License, or dnl (at your option) any later version. dnl dnl This program is distributed in the hope that it will be useful, but dnl WITHOUT ANY WARRANTY; without even the implied warranty of dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU dnl General Public License for more details. dnl dnl You should have received a copy of the GNU General Public License dnl along with this program; if not, write to the Free Software dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA dnl 02111-1307, USA. dnl dnl As a special exception to the GNU General Public License, if you dnl distribute this file as part of a program that contains a dnl configuration script generated by Autoconf, you may include it under dnl the same distribution terms that you use for the rest of that dnl program. dnl PKG_PREREQ(MIN-VERSION) dnl ----------------------- dnl Since: 0.29 dnl dnl Verify that the version of the pkg-config macros are at least dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's dnl installed version of pkg-config, this checks the developer's version dnl of pkg.m4 when generating configure. dnl dnl To ensure that this macro is defined, also add: dnl m4_ifndef([PKG_PREREQ], dnl [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])]) dnl dnl See the "Since" comment for each macro you use to see what version dnl of the macros you require. m4_defun([PKG_PREREQ], [m4_define([PKG_MACROS_VERSION], [0.29.2]) m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1, [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])]) ])dnl PKG_PREREQ dnl PKG_PROG_PKG_CONFIG([MIN-VERSION]) dnl ---------------------------------- dnl Since: 0.16 dnl dnl Search for the pkg-config tool and set the PKG_CONFIG variable to dnl first found in the path. Checks that the version of pkg-config found dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is dnl used since that's the first version where most current features of dnl pkg-config existed. AC_DEFUN([PKG_PROG_PKG_CONFIG], [m4_pattern_forbid([^_?PKG_[A-Z_]+$]) m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) fi if test -n "$PKG_CONFIG"; then _pkg_min_version=m4_default([$1], [0.9.0]) AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) PKG_CONFIG="" fi fi[]dnl ])dnl PKG_PROG_PKG_CONFIG dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) dnl ------------------------------------------------------------------- dnl Since: 0.18 dnl dnl Check to see whether a particular set of modules exists. Similar to dnl PKG_CHECK_MODULES(), but does not set variables or print errors. dnl dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) dnl only at the first occurence in configure.ac, so if the first place dnl it's called might be skipped (such as if it is within an "if", you dnl have to call PKG_CHECK_EXISTS manually AC_DEFUN([PKG_CHECK_EXISTS], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl if test -n "$PKG_CONFIG" && \ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then m4_default([$2], [:]) m4_ifvaln([$3], [else $3])dnl fi]) dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) dnl --------------------------------------------- dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting dnl pkg_failed based on the result. m4_define([_PKG_CONFIG], [if test -n "$$1"; then pkg_cv_[]$1="$$1" elif test -n "$PKG_CONFIG"; then PKG_CHECK_EXISTS([$3], [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes ], [pkg_failed=yes]) else pkg_failed=untried fi[]dnl ])dnl _PKG_CONFIG dnl _PKG_SHORT_ERRORS_SUPPORTED dnl --------------------------- dnl Internal check to see if pkg-config supports short errors. AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], [AC_REQUIRE([PKG_PROG_PKG_CONFIG]) if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi[]dnl ])dnl _PKG_SHORT_ERRORS_SUPPORTED dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], dnl [ACTION-IF-NOT-FOUND]) dnl -------------------------------------------------------------- dnl Since: 0.4.0 dnl dnl Note that if there is a possibility the first call to dnl PKG_CHECK_MODULES might not happen, you should be sure to include an dnl explicit call to PKG_PROG_PKG_CONFIG in your configure.ac AC_DEFUN([PKG_CHECK_MODULES], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl pkg_failed=no AC_MSG_CHECKING([for $2]) _PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) _PKG_CONFIG([$1][_LIBS], [libs], [$2]) m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS and $1[]_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details.]) if test $pkg_failed = yes; then AC_MSG_RESULT([no]) _PKG_SHORT_ERRORS_SUPPORTED if test $_pkg_short_errors_supported = yes; then $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` else $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD m4_default([$4], [AC_MSG_ERROR( [Package requirements ($2) were not met: $$1_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. _PKG_TEXT])[]dnl ]) elif test $pkg_failed = untried; then AC_MSG_RESULT([no]) m4_default([$4], [AC_MSG_FAILURE( [The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. _PKG_TEXT To get pkg-config, see .])[]dnl ]) else $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS $1[]_LIBS=$pkg_cv_[]$1[]_LIBS AC_MSG_RESULT([yes]) $3 fi[]dnl ])dnl PKG_CHECK_MODULES dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], dnl [ACTION-IF-NOT-FOUND]) dnl --------------------------------------------------------------------- dnl Since: 0.29 dnl dnl Checks for existence of MODULES and gathers its build flags with dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags dnl and VARIABLE-PREFIX_LIBS from --libs. dnl dnl Note that if there is a possibility the first call to dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to dnl include an explicit call to PKG_PROG_PKG_CONFIG in your dnl configure.ac. AC_DEFUN([PKG_CHECK_MODULES_STATIC], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl _save_PKG_CONFIG=$PKG_CONFIG PKG_CONFIG="$PKG_CONFIG --static" PKG_CHECK_MODULES($@) PKG_CONFIG=$_save_PKG_CONFIG[]dnl ])dnl PKG_CHECK_MODULES_STATIC dnl PKG_INSTALLDIR([DIRECTORY]) dnl ------------------------- dnl Since: 0.27 dnl dnl Substitutes the variable pkgconfigdir as the location where a module dnl should install pkg-config .pc files. By default the directory is dnl $libdir/pkgconfig, but the default can be changed by passing dnl DIRECTORY. The user can override through the --with-pkgconfigdir dnl parameter. AC_DEFUN([PKG_INSTALLDIR], [m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])]) m4_pushdef([pkg_description], [pkg-config installation directory @<:@]pkg_default[@:>@]) AC_ARG_WITH([pkgconfigdir], [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],, [with_pkgconfigdir=]pkg_default) AC_SUBST([pkgconfigdir], [$with_pkgconfigdir]) m4_popdef([pkg_default]) m4_popdef([pkg_description]) ])dnl PKG_INSTALLDIR dnl PKG_NOARCH_INSTALLDIR([DIRECTORY]) dnl -------------------------------- dnl Since: 0.27 dnl dnl Substitutes the variable noarch_pkgconfigdir as the location where a dnl module should install arch-independent pkg-config .pc files. By dnl default the directory is $datadir/pkgconfig, but the default can be dnl changed by passing DIRECTORY. The user can override through the dnl --with-noarch-pkgconfigdir parameter. AC_DEFUN([PKG_NOARCH_INSTALLDIR], [m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])]) m4_pushdef([pkg_description], [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@]) AC_ARG_WITH([noarch-pkgconfigdir], [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],, [with_noarch_pkgconfigdir=]pkg_default) AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir]) m4_popdef([pkg_default]) m4_popdef([pkg_description]) ])dnl PKG_NOARCH_INSTALLDIR dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE, dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) dnl ------------------------------------------- dnl Since: 0.28 dnl dnl Retrieves the value of the pkg-config variable for the given module. AC_DEFUN([PKG_CHECK_VAR], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl _PKG_CONFIG([$1], [variable="][$3]["], [$2]) AS_VAR_COPY([$1], [pkg_cv_][$1]) AS_VAR_IF([$1], [""], [$5], [$4])dnl ])dnl PKG_CHECK_VAR # Copyright (C) 2002-2021 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.16' 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.16.5], [], [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.16.5])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-2021 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], [AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl # Expand $ac_aux_dir to an absolute path. am_aux_dir=`cd "$ac_aux_dir" && pwd` ]) # AM_CONDITIONAL -*- Autoconf -*- # Copyright (C) 1997-2021 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_CONDITIONAL(NAME, SHELL-CONDITION) # ------------------------------------- # Define a conditional. AC_DEFUN([AM_CONDITIONAL], [AC_PREREQ([2.52])dnl m4_if([$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-2021 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. # 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", "OBJC", "OBJCXX", "UPC", or "GJC". # 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 m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], [$1], [CXX], [depcc="$CXX" am_compiler_list=], [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], [$1], [OBJCXX], [depcc="$OBJCXX" 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". rm -rf conftest.dir 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 10 /bin/sh. echo '/* dummy */' > 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 ;; msvc7 | msvc7msys | 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], [dnl AS_HELP_STRING( [--enable-dependency-tracking], [do not reject slow dependency extractors]) AS_HELP_STRING( [--disable-dependency-tracking], [speeds up one-time build])]) if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) AC_SUBST([AMDEPBACKSLASH])dnl _AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl AC_SUBST([am__nodep])dnl _AM_SUBST_NOTMAKE([am__nodep])dnl ]) # Generate code to set up dependency tracking. -*- Autoconf -*- # Copyright (C) 1999-2021 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_OUTPUT_DEPENDENCY_COMMANDS # ------------------------------ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], [{ # Older Autoconf 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. # TODO: see whether this extra hack can be removed once we start # requiring Autoconf 2.70 or later. AS_CASE([$CONFIG_FILES], [*\'*], [eval set x "$CONFIG_FILES"], [*], [set x $CONFIG_FILES]) shift # Used to flag and report bootstrapping failures. am_rc=0 for am_mf do # Strip MF so we end up with the name of the file. am_mf=`AS_ECHO(["$am_mf"]) | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile which includes # dependency-tracking related rules and includes. # Grep'ing the whole file directly is not great: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ || continue am_dirpart=`AS_DIRNAME(["$am_mf"])` am_filepart=`AS_BASENAME(["$am_mf"])` AM_RUN_LOG([cd "$am_dirpart" \ && sed -e '/# am--include-marker/d' "$am_filepart" \ | $MAKE -f - am--depfiles]) || am_rc=$? done if test $am_rc -ne 0; then AC_MSG_FAILURE([Something went wrong bootstrapping makefile fragments for automatic dependency tracking. If GNU make was not used, consider re-running the configure script with MAKE="gmake" (or whatever is necessary). You can also try re-running configure with the '--disable-dependency-tracking' option to at least be able to build the package (albeit without support for automatic dependency tracking).]) fi AS_UNSET([am_dirpart]) AS_UNSET([am_filepart]) AS_UNSET([am_mf]) AS_UNSET([am_rc]) rm -f conftest-deps.mk } ])# _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. # This creates each '.Po' and '.Plo' makefile fragment that we'll 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" MAKE="${MAKE-make}"])]) # Do all the work for Automake. -*- Autoconf -*- # Copyright (C) 1996-2021 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 macro actually does too much. Some checks are only needed if # your package does certain things. But this isn't really a big deal. dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O. m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC]) [_AM_PROG_CC_C_O ]) # 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.65])dnl m4_ifdef([_$0_ALREADY_INIT], [m4_fatal([$0 expanded multiple times ]m4_defn([_$0_ALREADY_INIT]))], [m4_define([_$0_ALREADY_INIT], m4_expansion_stack)])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], [AC_DIAGNOSE([obsolete], [$0: two- and three-arguments forms are deprecated.]) 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_ifset([AC_PACKAGE_NAME], [ok]):m4_ifset([AC_PACKAGE_VERSION], [ok]), [ok:ok],, [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([AC_PROG_MKDIR_P])dnl # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # AC_SUBST([mkdir_p], ['$(MKDIR_P)']) # We need awk for the "check" target (and possibly the TAP driver). 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])], [m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_CXX], [_AM_DEPENDENCIES([CXX])], [m4_define([AC_PROG_CXX], m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJC], [_AM_DEPENDENCIES([OBJC])], [m4_define([AC_PROG_OBJC], m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], [_AM_DEPENDENCIES([OBJCXX])], [m4_define([AC_PROG_OBJCXX], m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl ]) # Variables for tags utilities; see am/tags.am if test -z "$CTAGS"; then CTAGS=ctags fi AC_SUBST([CTAGS]) if test -z "$ETAGS"; then ETAGS=etags fi AC_SUBST([ETAGS]) if test -z "$CSCOPE"; then CSCOPE=cscope fi AC_SUBST([CSCOPE]) AC_REQUIRE([AM_SILENT_RULES])dnl dnl The testsuite driver may need to know about EXEEXT, so add the dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This dnl macro 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 # POSIX will say in a future version that running "rm -f" with no argument # is OK; and we want to be able to make that assumption in our Makefile # recipes. So use an aggressive probe to check that the usage we want is # actually supported "in the wild" to an acceptable degree. # See automake bug#10828. # To make any issue more visible, cause the running configure to be aborted # by default if the 'rm' program in use doesn't match our expectations; the # user can still override this though. if rm -f && rm -fr && rm -rf; then : OK; else cat >&2 <<'END' Oops! Your 'rm' program seems unable to run without file operands specified on the command line, even when the '-f' option is present. This is contrary to the behaviour of most rm programs out there, and not conforming with the upcoming POSIX standard: Please tell bug-automake@gnu.org about your system, including the value of your $PATH and any error possibly output before this message. This can help us improve future automake versions. END if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then echo 'Configuration will proceed anyway, since you have set the' >&2 echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 echo >&2 else cat >&2 <<'END' Aborting the configuration process, to ensure you take notice of the issue. You can download and install GNU coreutils to get an 'rm' implementation that behaves properly: . If you want to complete the configuration process using your problematic 'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM to "yes", and re-run configure. END AC_MSG_ERROR([Your 'rm' program is bad, sorry.]) fi fi dnl The trailing newline in this macro's definition is deliberate, for dnl backward compatibility and to allow trailing 'dnl'-style comments dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841. ]) 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-2021 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+set}" != 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-2021 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. # 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])]) # Check to see how 'make' treats includes. -*- Autoconf -*- # Copyright (C) 2001-2021 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_MAKE_INCLUDE() # ----------------- # Check whether make has an 'include' directive that can support all # the idioms we need for our automatic dependency tracking code. AC_DEFUN([AM_MAKE_INCLUDE], [AC_MSG_CHECKING([whether ${MAKE-make} supports the include directive]) cat > confinc.mk << 'END' am__doit: @echo this is the am__doit target >confinc.out .PHONY: am__doit END am__include="#" am__quote= # BSD make does it like this. echo '.include "confinc.mk" # ignored' > confmf.BSD # Other make implementations (GNU, Solaris 10, AIX) do it like this. echo 'include confinc.mk # ignored' > confmf.GNU _am_result=no for s in GNU BSD; do AM_RUN_LOG([${MAKE-make} -f confmf.$s && cat confinc.out]) AS_CASE([$?:`cat confinc.out 2>/dev/null`], ['0:this is the am__doit target'], [AS_CASE([$s], [BSD], [am__include='.include' am__quote='"'], [am__include='include' am__quote=''])]) if test "$am__include" != "#"; then _am_result="yes ($s style)" break fi done rm -f confinc.* confmf.* AC_MSG_RESULT([${_am_result}]) AC_SUBST([am__include])]) AC_SUBST([am__quote])]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- # Copyright (C) 1997-2021 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_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 is modern enough. # If it is, 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 MISSING="\${SHELL} '$am_aux_dir/missing'" fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= AC_MSG_WARN(['missing' script is too old or missing]) fi ]) # Helper functions for option handling. -*- Autoconf -*- # Copyright (C) 2001-2021 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_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])]) # Copyright (C) 1999-2021 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_CC_C_O # --------------- # Like AC_PROG_CC_C_O, but changed for automake. We rewrite AC_PROG_CC # to automatically call this. AC_DEFUN([_AM_PROG_CC_C_O], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([compile])dnl AC_LANG_PUSH([C])dnl AC_CACHE_CHECK( [whether $CC understands -c and -o together], [am_cv_prog_cc_c_o], [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])]) # Make sure it works both with $CC and with simple cc. # Following AC_PROG_CC_C_O, we do the test twice because some # compilers refuse to overwrite an existing .o file with -o, # though they will create one. am_cv_prog_cc_c_o=yes for am_i in 1 2; do if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \ && test -f conftest2.$ac_objext; then : OK else am_cv_prog_cc_c_o=no break fi done rm -f core conftest* unset am_i]) if test "$am_cv_prog_cc_c_o" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi AC_LANG_POP([C])]) # For backward compatibility. AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) # Copyright (C) 2001-2021 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_RUN_LOG(COMMAND) # ------------------- # Run COMMAND, save the exit status in ac_status, and log it. # (This has been adapted from Autoconf's _AC_RUN_LOG macro.) AC_DEFUN([AM_RUN_LOG], [{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD (exit $ac_status); }]) # Check to make sure that the build environment is sane. -*- Autoconf -*- # Copyright (C) 1996-2021 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_SANITY_CHECK # --------------- AC_DEFUN([AM_SANITY_CHECK], [AC_MSG_CHECKING([whether build environment is sane]) # 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 ( am_has_slept=no for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file 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 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 if test "$[2]" = conftest.file || test $am_try -eq 2; then break fi # Just in case. sleep 1 am_has_slept=yes done 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]) # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if grep 'slept: no' conftest.file >/dev/null 2>&1; then ( sleep 1 ) & am_sleep_pid=$! fi AC_CONFIG_COMMANDS_PRE( [AC_MSG_CHECKING([that generated files are newer than configure]) if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi AC_MSG_RESULT([done])]) rm -f conftest.file ]) # Copyright (C) 2009-2021 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_SILENT_RULES([DEFAULT]) # -------------------------- # Enable less verbose build rules; with the default set to DEFAULT # ("yes" being less verbose, "no" or empty being verbose). AC_DEFUN([AM_SILENT_RULES], [AC_ARG_ENABLE([silent-rules], [dnl AS_HELP_STRING( [--enable-silent-rules], [less verbose build output (undo: "make V=1")]) AS_HELP_STRING( [--disable-silent-rules], [verbose build output (undo: "make V=0")])dnl ]) case $enable_silent_rules in @%:@ ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; esac dnl dnl A few 'make' implementations (e.g., NonStop OS and NextStep) dnl do not support nested variable expansions. dnl See automake bug#9928 and bug#10237. am_make=${MAKE-make} AC_CACHE_CHECK([whether $am_make supports nested variables], [am_cv_make_support_nested_variables], [if AS_ECHO([['TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi]) if test $am_cv_make_support_nested_variables = yes; then dnl Using '$V' instead of '$(V)' breaks IRIX make. AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AC_SUBST([AM_V])dnl AM_SUBST_NOTMAKE([AM_V])dnl AC_SUBST([AM_DEFAULT_V])dnl AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl AC_SUBST([AM_DEFAULT_VERBOSITY])dnl AM_BACKSLASH='\' AC_SUBST([AM_BACKSLASH])dnl _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl ]) # Copyright (C) 2001-2021 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-2021 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_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-2021 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_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. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AC_SUBST([AMTAR], ['$${TAR-tar}']) # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' m4_if([$1], [v7], [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], [m4_case([$1], [ustar], [# The POSIX 1988 'ustar' format is defined with fixed-size fields. # There is notably a 21 bits limit for the UID and the GID. In fact, # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 # and bug#13588). am_max_uid=2097151 # 2^21 - 1 am_max_gid=$am_max_uid # The $UID and $GID variables are not portable, so we need to resort # to the POSIX-mandated id(1) utility. Errors in the 'id' calls # below are definitely unexpected, so allow the users to see them # (that is, avoid stderr redirection). am_uid=`id -u || echo unknown` am_gid=`id -g || echo unknown` AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) if test $am_uid -le $am_max_uid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) if test $am_gid -le $am_max_gid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi], [pax], [], [m4_fatal([Unknown tar format])]) AC_MSG_CHECKING([how to create a $1 tar archive]) # Go ahead even if we have the value already cached. We do so because we # need to set the values for the 'am__tar' and 'am__untar' variables. _am_tools=${am_cv_prog_tar_$1-$_am_tools} 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([acinclude.m4]) isync-1.4.4/autodefs.h.in0000644000175000001440000000502314152373731012160 00000000000000/* autodefs.h.in. Generated from configure.ac by autoheader. */ /* Define to 1 if you have the `getaddrinfo' function. */ #undef HAVE_GETADDRINFO /* Define to 1 if you have the `inet_ntop' function. */ #undef HAVE_INET_NTOP /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* if your libc has IPv6 support */ #undef HAVE_IPV6 /* if you have the SASL libraries */ #undef HAVE_LIBSASL /* if you have the OpenSSL libraries */ #undef HAVE_LIBSSL /* if you have the zlib library */ #undef HAVE_LIBZ /* Define to 1 if you have the macOS Keychain Services API. */ #undef HAVE_MACOS_KEYCHAIN /* Define to 1 if you have the `memrchr' function. */ #undef HAVE_MEMRCHR /* Define to 1 if you have the header file. */ #undef HAVE_POLL_H /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDIO_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the `strnlen' function. */ #undef HAVE_STRNLEN /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SELECT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the `timegm' function. */ #undef HAVE_TIMEGM /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define to 1 if you have the `vasprintf' function. */ #undef HAVE_VASPRINTF /* Name of package */ #undef PACKAGE /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Define to 1 if all of the C90 standard headers exist (not just the ones required in a freestanding environment). This macro is provided for backward compatibility; new code need not use it. */ #undef STDC_HEADERS /* if Berkeley DB should be used */ #undef USE_DB /* Version number of package */ #undef VERSION isync-1.4.4/configure.ac0000644000175000001440000001645714152373720012071 00000000000000AC_INIT([isync], [1.4.4]) AC_CONFIG_HEADERS([autodefs.h]) AC_CANONICAL_TARGET AM_INIT_AUTOMAKE AM_MAINTAINER_MODE AC_PROG_CC if test "$GCC" = yes; then warnings=" -Wall -Wextra -Wshadow -Wcast-qual -Wformat=2 -Wformat-signedness -Wformat-nonliteral -Wstrict-prototypes -Wno-overlength-strings " CFLAGS="$CFLAGS -pipe -std=c11 -pedantic $(echo $warnings)" fi AC_COMPILE_IFELSE([AC_LANG_SOURCE([ void fkt(void) { int a = 42; // c99 comment for (int i = 0; i < a; i++) {} // declaration inside for() int b; // declaration after code } // c11 anonymous structs/unions struct base { int a; }; union deriv { struct base gen; struct { int a; int b; }; }; ])], , [AC_MSG_ERROR([compiler does not support required C11 features])]) CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE" AC_CHECK_PROG(PERL, perl, perl) if test "x$PERL" = "x"; then AC_MSG_ERROR([perl not found]) fi need_perl=5.14 AC_CACHE_CHECK([whether perl is recent enough], ob_cv_perl_ver, [ if $PERL -e "use v$need_perl;" 2> /dev/null; then ob_cv_perl_ver=yes else ob_cv_perl_ver=no fi ]) if test "x$ob_cv_perl_ver" = "xno"; then AC_MSG_ERROR([perl is too old, need v$need_perl]) fi AC_CACHE_CHECK([whether strftime supports %z], ob_cv_strftime_z, [AC_RUN_IFELSE([AC_LANG_SOURCE([[ #include #include int main(void) { time_t t = 0; char buf[32]; strftime(buf, sizeof(buf), "%z", localtime(&t)); return !(buf[0] == '+' || buf[0] == '-'); } ]])], [ob_cv_strftime_z=yes], [ob_cv_strftime_z=no], [ob_cv_strftime_z="yes (assumed)"])]) if test "x$ob_cv_strftime_z" = x"no"; then AC_MSG_ERROR([libc lacks necessary feature]) fi AC_CHECK_HEADERS(poll.h sys/select.h) AC_CHECK_FUNCS(vasprintf strnlen memrchr timegm) AC_CHECK_LIB(socket, socket, [SOCK_LIBS="-lsocket"]) AC_CHECK_LIB(nsl, inet_ntoa, [SOCK_LIBS="$SOCK_LIBS -lnsl"]) AC_SUBST(SOCK_LIBS) have_ipv6=true sav_LIBS=$LIBS LIBS="$LIBS $SOCK_LIBS" AC_CHECK_FUNCS(getaddrinfo inet_ntop, , [have_ipv6=false]) LIBS=$sav_LIBS if $have_ipv6; then AC_DEFINE(HAVE_IPV6, 1, [if your libc has IPv6 support]) fi have_ssl_paths= AC_ARG_WITH(ssl, AS_HELP_STRING([--with-ssl[=PATH]], [where to look for SSL [detect]]), [ob_cv_with_ssl=$withval]) if test "x$ob_cv_with_ssl" != xno; then case $ob_cv_with_ssl in ""|yes) dnl Detect the pkg-config tool, as it may have extra info about the openssl dnl installation we can use. I *believe* this is what we are expected to do dnl on really recent Redhat Linux hosts. PKG_PROG_PKG_CONFIG if test "x$PKG_CONFIG" != "x" ; then AC_MSG_CHECKING([OpenSSL presence with pkg-config]) if $PKG_CONFIG --exists openssl; then SSL_LIBS=`$PKG_CONFIG --libs-only-l openssl` SSL_LDFLAGS=`$PKG_CONFIG --libs-only-L openssl` SSL_CPPFLAGS=`$PKG_CONFIG --cflags-only-I openssl` have_ssl_paths=yes AC_MSG_RESULT([found]) else AC_MSG_RESULT([not found]) fi fi ;; *) SSL_LDFLAGS=-L$ob_cv_with_ssl/lib$libsuff SSL_CPPFLAGS=-I$ob_cv_with_ssl/include ;; esac if test -z "$have_ssl_paths"; then sav_LDFLAGS=$LDFLAGS LDFLAGS="$LDFLAGS $SSL_LDFLAGS" AC_CHECK_LIB(dl, dlopen, [LIBDL=-ldl]) AC_CHECK_LIB(crypto, X509_cmp, [LIBCRYPTO=-lcrypto]) AC_CHECK_LIB(ssl, SSL_connect, [SSL_LIBS="-lssl $LIBCRYPTO $LIBDL" have_ssl_paths=yes]) LDFLAGS=$sav_LDFLAGS fi sav_CPPFLAGS=$CPPFLAGS CPPFLAGS="$CPPFLAGS $SSL_CPPFLAGS" AC_CHECK_HEADER(openssl/ssl.h, , [have_ssl_paths=]) CPPFLAGS=$sav_CPPFLAGS if test -z "$have_ssl_paths"; then if test -n "$ob_cv_with_ssl"; then AC_MSG_ERROR([OpenSSL libs and/or includes were not found where specified]) fi else AC_DEFINE(HAVE_LIBSSL, 1, [if you have the OpenSSL libraries]) CPPFLAGS="$CPPFLAGS $SSL_CPPFLAGS" LDFLAGS="$LDFLAGS $SSL_LDFLAGS" fi fi AC_SUBST(SSL_LIBS) have_sasl_paths= AC_ARG_WITH(sasl, AS_HELP_STRING([--with-sasl[=PATH]], [where to look for SASL [detect]]), [ob_cv_with_sasl=$withval]) if test "x$ob_cv_with_sasl" != xno; then case $ob_cv_with_sasl in ""|yes) dnl FIXME: Try various possible paths here... ;; *) SASL_LDFLAGS=-L$ob_cv_with_sasl/lib$libsuff SASL_CPPFLAGS=-I$ob_cv_with_sasl/include ;; esac if test -z "$have_sasl_paths"; then sav_LDFLAGS=$LDFLAGS LDFLAGS="$LDFLAGS $SASL_LDFLAGS" AC_CHECK_LIB(sasl2, sasl_client_init, [SASL_LIBS="-lsasl2" have_sasl_paths=yes]) LDFLAGS=$sav_LDFLAGS fi sav_CPPFLAGS=$CPPFLAGS CPPFLAGS="$CPPFLAGS $SASL_CPPFLAGS" AC_CHECK_HEADER(sasl/sasl.h, , [have_sasl_paths=]) CPPFLAGS=$sav_CPPFLAGS if test -z "$have_sasl_paths"; then if test -n "$ob_cv_with_sasl"; then AC_MSG_ERROR([SASL libs and/or includes were not found where specified]) fi else AC_DEFINE(HAVE_LIBSASL, 1, [if you have the SASL libraries]) CPPFLAGS="$CPPFLAGS $SASL_CPPFLAGS" LDFLAGS="$LDFLAGS $SASL_LDFLAGS" fi fi AC_SUBST(SASL_LIBS) AC_CACHE_CHECK([for Berkeley DB >= 4.1], ac_cv_berkdb4, [ac_cv_berkdb4=no sav_LIBS=$LIBS LIBS="$LIBS -ldb" AC_LINK_IFELSE([AC_LANG_PROGRAM( [#include ], [DB *db; db_create(&db, 0, 0); db->truncate(db, 0, 0, 0); db->open(db, 0, "foo", "foo", DB_HASH, DB_CREATE, 0); ])], [ac_cv_berkdb4=yes], []) LIBS=$sav_LIBS ]) if test "x$ac_cv_berkdb4" = xyes; then AC_SUBST([DB_LIBS], ["-ldb"]) AC_DEFINE(USE_DB, 1, [if Berkeley DB should be used]) fi have_zlib= AC_ARG_WITH(zlib, AS_HELP_STRING([--with-zlib], [use zlib [detect]]), [ob_cv_with_zlib=$withval]) if test "x$ob_cv_with_zlib" != xno; then AC_CHECK_LIB([z], [deflate], [AC_CHECK_HEADER(zlib.h, [have_zlib=1 AC_SUBST([Z_LIBS], ["-lz"]) AC_DEFINE([HAVE_LIBZ], 1, [if you have the zlib library])] )] ) fi AM_CONDITIONAL(with_mdconvert, test "x$ac_cv_berkdb4" = xyes) case $target_os in darwin*) darwin=yes ;; *) darwin=no ;; esac AC_ARG_WITH( macos-keychain, [AS_HELP_STRING([--with-macos-keychain], [Support macOS keychain])], [have_macos_keychain=$withval], [have_macos_keychain=$darwin]) if test "x$have_macos_keychain" != xno; then if test $darwin = no; then AC_MSG_ERROR([Cannot use macOS Keychain outside macOS.]) fi have_macos_keychain=yes AC_DEFINE(HAVE_MACOS_KEYCHAIN, 1, [Define to 1 if you have the macOS Keychain Services API.]) AC_SUBST(KEYCHAIN_LIBS, ["-Wl,-framework,Security,-framework,CoreFoundation"]) fi AC_CONFIG_FILES([Makefile src/Makefile isync.spec]) AC_OUTPUT AC_MSG_RESULT() if test -n "$have_ssl_paths"; then AC_MSG_RESULT([Using SSL]) else AC_MSG_RESULT([Not using SSL]) fi if test -n "$have_sasl_paths"; then AC_MSG_RESULT([Using SASL]) else AC_MSG_RESULT([Not using SASL]) fi if test -n "$have_zlib"; then AC_MSG_RESULT([Using zlib]) else AC_MSG_RESULT([Not using zlib]) fi if test "x$ac_cv_berkdb4" = xyes; then AC_MSG_RESULT([Using Berkeley DB]) else AC_MSG_RESULT([Not using Berkeley DB]) fi if test $darwin = yes; then if test "x$have_macos_keychain" = xyes; then AC_MSG_RESULT([Using macOS Keychain]) else AC_MSG_RESULT([Not using macOS Keychain]) fi fi AC_MSG_RESULT() isync-1.4.4/Makefile.am0000644000175000001440000000520114006611550011612 00000000000000SUBDIRS = src bin_SCRIPTS = mbsync-get-cert EXTRA_DIST = debian isync.spec $(bin_SCRIPTS) LOG_PL = \ use POSIX qw(strftime); \ use Date::Parse; \ use Text::Wrap; \ $$Text::Wrap::columns = 72; \ while (defined($$_ = <>)) { \ /^commit / or die "commit missing: $$_"; \ <> =~ /^log size (\d+)$$/ or die "wrong size"; \ $$len = $$1; \ read(STDIN, $$log, $$len) == $$len or die "unexpected EOF"; \ $$log =~ s/^Author: ([^>]+>)\nDate: (\d{4}-\d\d-\d\d \d\d:\d\d:\d\d [-+]\d{4})\n(.*)$$/$$3/s or die "unexpected log format"; \ $$author = $$1; $$date = str2time($$2); \ scalar(<>); \ @files = (); \ $$pfx = ""; \ while (defined($$l = <>) and $$l ne "\n") { \ chomp $$l; \ next if ($$l =~ m,^(ChangeLog$$|NEWS$$|TODO$$|debian/),); \ if (!@files) { \ $$pfx = $$l; \ $$pfx =~ s,/?[^/]+$$,,; \ } else { \ while (length($$pfx)) { \ $$l =~ m,^\Q$$pfx/\E, and last; \ $$pfx =~ s,/?[^/]+$$,,; \ } \ } \ push @files, $$l; \ } \ next if (!@files); \ print strftime("%F %H:%M", gmtime($$date))." ".$$author."\n\n"; \ if (@files > 1 and ($$len = length($$pfx))) { \ @efiles = (); \ for $$f (@files) { push @efiles, substr($$f, $$len + 1); } \ $$fstr = $$pfx."/: "; \ } else { \ @efiles = @files; \ $$fstr = ""; \ } \ print wrap("\t* ", "\t ", $$fstr.join(", ", @efiles).":")."\n"; \ $$log =~ s, +$$,,gm; \ $$log =~ s,^ ,\t,gm; \ print $$log."\n"; \ } $(srcdir)/.git/index: $(srcdir)/ChangeLog: $(srcdir)/.git/index $(MAKE) log log: @test -z "$(srcdir)" || cd $(srcdir) && \ ( ! test -d .git || \ git log --pretty=medium --date=iso --log-size --name-only --no-merges | \ perl -e '$(LOG_PL)' > ChangeLog ) cov-scan: clean /opt/cov-analysis-*/bin/cov-build --dir cov-int $(MAKE) tar cavf isync-cov.tar.xz cov-int deb: CFLAGS= INSTALL= dpkg-buildpackage -b --no-sign dist-hook: find $(distdir)/debian \( -name .#\*# -o -type l \) -print0 | xargs -0r rm -rf -cd $(distdir)/debian && test -f .gitignore && rm -rf `cut -c2- .gitignore` .gitignore dist-sign: dist gpg -b -a $(PACKAGE)-$(VERSION).tar.gz rpm: dist CFLAGS="-O2 -mtune=core2" rpmbuild --clean -ta $(PACKAGE)-$(VERSION).tar.gz rpm-ia32: dist CFLAGS="-O2 -m32 -march=i686" rpmbuild --target i686-unknown-linux --clean -ta $(PACKAGE)-$(VERSION).tar.gz doc_DATA = README TODO NEWS ChangeLog AUTHORS isync-1.4.4/debian/0000755000175000001440000000000014152374120011063 500000000000000isync-1.4.4/debian/rules0000755000175000001440000000023014006611550012055 00000000000000#!/usr/bin/make -f %: dh $@ --with=autoreconf override_dh_auto_install: dh_auto_install $(RM) $(CURDIR)/debian/isync/usr/share/doc/isync/ChangeLog isync-1.4.4/debian/source/0000755000175000001440000000000014006611550012362 500000000000000isync-1.4.4/debian/source/format0000644000175000001440000000001414006611550013510 000000000000003.0 (quilt) isync-1.4.4/debian/compat0000644000175000001440000000000214006611550012200 000000000000009 isync-1.4.4/debian/control0000644000175000001440000000253514006611550012412 00000000000000Source: isync Section: mail Priority: optional Maintainer: Nicolas Boullis Uploaders: Theodore Y. Ts'o , Alessandro Ghedini Standards-Version: 3.9.8 Build-Depends: debhelper (>= 9), dh-autoreconf, libdb-dev, libsasl2-dev, libssl-dev, pkg-config, zlib1g-dev Vcs-Git: https://anonscm.debian.org/git/collab-maint/isync.git Vcs-Browser: https://anonscm.debian.org/gitweb/?p=collab-maint/isync.git Homepage: http://isync.sourceforge.net/ Package: isync Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Suggests: mutt Description: IMAP and MailDir mailbox synchronizer mbsync/isync is a command line application which synchronizes mailboxes; currently Maildir and IMAP4 mailboxes are supported. New messages, message deletions and flag changes can be propagated both ways. isync is suitable for use in IMAP-disconnected mode. . Features: * Fine-grained selection of synchronization operations to perform * Synchronizes single mailboxes or entire mailbox collections * Partial mirrors possible: keep only the latest messages locally * Trash functionality: backup messages before removing them IMAP features: * Security: supports TLS/SSL via imaps: (port 993) and STARTTLS; SASL for authentication * Supports NAMESPACE for simplified configuration * Pipelining for maximum speed isync-1.4.4/debian/changelog0000644000175000001440000003112614006611550012657 00000000000000isync (1.2.3-0) unstable; urgency=low * Upload to unstable (with urgency=low) -- Oswald Buddenhagen Sun, 01 Oct 2017 12:12:12 +0000 isync (1.2.1-2) unstable; urgency=low * Upload to unstable (with urgency=low) * Don't call uupdate after uscan * Import patch to fix build with OpenSSL 1.1 (Closes: #828357) * Bump Standards-Version to 3.9.8 (no changes needed) * Add pkg-config to Build-Depends * Update Vcs-* URLs * Fix spelling-error-in-binary -- Alessandro Ghedini Sat, 19 Nov 2016 17:14:42 +0000 isync (1.2.1-1) experimental; urgency=medium [ Evgeni Golov ] * New upstream release. * Explicitly Build-Depend on zlib1g-dev -- Alessandro Ghedini Sat, 09 Jan 2016 12:56:39 +0000 isync (1.2.0-1) experimental; urgency=medium * New upstream release - Only show sync progress by default (Closes: #765052) * Enable libsasl support -- Alessandro Ghedini Mon, 06 Apr 2015 13:42:24 +0200 isync (1.1.2-1) unstable; urgency=medium * New upstream release * Bump Standards-Version to 3.9.6 (no changes needed) -- Alessandro Ghedini Sun, 01 Feb 2015 20:42:25 +0100 isync (1.1.1-1) unstable; urgency=medium * New upstream release - Don't lie about the default of User (Closes: #744389) - Don't forget to reset message counts when skipping scan (Closes: #744259) - Rework maildir store mapping (Closes: #737708) * Drop 01_fix-manpages.patch (merged upstream) * Drop 02_fix-empty-folder-sync.patch (merged upstream) -- Alessandro Ghedini Tue, 03 Jun 2014 21:00:44 +0200 isync (1.1.0-2) unstable; urgency=medium * Drop 02_fix-duplicate-changelog.patch (rm the file after installation instead) * Update 01_fix-manpages.patch * Add 02_fix-empty-folder-sync.patch (Closes: #738873) -- Alessandro Ghedini Fri, 14 Feb 2014 20:41:49 +0100 isync (1.1.0-1) unstable; urgency=low * New upstream release (Closes: #674403) - Fix overlapping memcpy (Closes: #650373) - Fix segfault while syncing mailboxes (Closes: #411120) - Fix segfault when invoked with arguments without configuration (Closes: #727239) * Bump debhelper compat level, update Build-Depends * Switch to short-form dh rules, remove useless files * Switch to 3.0 (quilt) source format * Remove empty patches/ directory * Drop local source modifications * Update short/long descriptions * Add 01_fix-manpages.patch to fix manpage errors and typos * Add Homepage field * Update copyright file to Copyright-Format 1.0 * Add Vcs-* fields * Add 02_fix-duplicate-changelog.patch to avoid duplicate changelog install * Add myself to Uploaders * Bump Standards-Version to 3.9.5 (no changes needed) * Use dh-autoreconf instead of autotools-dev -- Alessandro Ghedini Sun, 12 Jan 2014 16:35:52 +0100 isync (1.0.4-2.2) unstable; urgency=low * Non-maintainer upload. * Apply upstream patch for CVE-2013-0289. Fix incorrect server's SSL x509.v3 certificate validation when performing IMAP synchronization. (Closes: #701052) -- Salvatore Bonaccorso Sun, 24 Feb 2013 09:27:55 +0100 isync (1.0.4-2.1) unstable; urgency=low * Non-maintainer upload. * Drop debconf note that deals with a pre-Etch transition. Closes: #492194 -- Christian Perrier Sat, 25 Oct 2008 08:40:52 +0200 isync (1.0.4-2) unstable; urgency=low * Change the libdb4.4-dev build-dependency to libdb-dev. Thanks Luk for pointing this. (Closes: #499165) -- Nicolas Boullis Wed, 17 Sep 2008 23:58:58 +0200 isync (1.0.4-1) unstable; urgency=low * The second "thanks Christian" release. * New upstream release. - Accept empty "* SEARCH" response. (Closes: #413336) - Quote user name in generated config. (Closes: #456783) * Explain the isync->mbsync change in the package description. (Closes: #430648) * Fix the debian/watch file that lacked the version and action fields. * Disable the upstream "deb-clean" stuff in the top-level Makefile, as in breaks cleaning the build directory. * Bump Standards-Version to 3.7.3. (No change required.) -- Nicolas Boullis Sat, 03 May 2008 01:42:55 +0200 isync (1.0.3-3.1) unstable; urgency=low * Non-maintainer upload to fix pending l10n issues. * Debconf translations: - Portuguese. Closes: #418283 - Italian. Closes: #418246 - Dutch. Closes: #422244 - Spanish. Closes: #426184 - Finnish. Closes: #468214 - Galician. Closes: #470529 * [Lintian] Do not include debian revision in the build dependency for libssl-dev * [Lintian] No longer ignore errors from "make distclean" -- Christian Perrier Wed, 12 Mar 2008 07:24:01 +0100 isync (1.0.3-3) unstable; urgency=low * The "thanks Christian" release. * Update German debconf templates translation. Thanks to Erik Schanze (for the translation) and Christian Perrier (for forwarding the translation). (Closes: #407615) -- Nicolas Boullis Mon, 5 Feb 2007 00:17:15 +0100 isync (1.0.3-2.1) unstable; urgency=low * Non-maintainer upload with maintainer's permission * Debconf templates translations: - French updated by me - Brazilian Portuguese translation added - Czech translation added. Closes: #403473 - Russian translation added. Closes: #403510 - Vietnamese translation added - Norwegian BokmÃ¥l translation added. Closes: #403523 -- Christian Perrier Sun, 17 Dec 2006 15:31:04 +0100 isync (1.0.3-2) unstable; urgency=low * Back to unstable, with permission from Steve Langasek. (Message-ID: <20061121015225.GF28035@borges.dodds.net>) * Rewrite the debconf note, thanks to the debian-l10n-english team (and especially MJ Ray). * Also add some information about the new version into NEWS.Debian. * Remove the information about the need to set the T (trashed) flag from README.Debian. * Also install the isyncrc.sample sample configuration file. * Bump Standards-Version to 3.7.2. (No change required.) -- Nicolas Boullis Tue, 5 Dec 2006 00:34:54 +0100 isync (1.0.3-1) experimental; urgency=low * New upstream release. (Closes: #315423) - Isync now supports breaking and linking threads. (Closes: #177280) - It also supports unflagging messages. (Closes: #111286) - IMAP commands are sent asynchronously. (Closes: #226222) * Kill the old debconf question about upgrades from pre-0.8 versions. * Use the (now obsolete) swedish and portugese translations anyway. (Closes: #337771, #378891) * New debconf note that warns about upgrades from pre-1.0 versions. * Add a build dependency on po-debconf. -- Nicolas Boullis Sun, 19 Nov 2006 15:04:31 +0100 isync (0.9.2-4) unstable; urgency=low * Add Czech debconf translation, thanks to Martin Šín. (Closes: #317571) * Build with the newest libssl-dev. * Load the debconf library in postinst to ensure that everything works as expected, thanks to lintian for noticing the problem and to Josselin Mouette for pointing to the right doc. * Fix a bashism in the config script, thanks to lintian. * Update the postal address of the FSF in the copyright file. * Bump Standards-Version to 3.6.2. (No change required.) -- Nicolas Boullis Mon, 10 Oct 2005 01:37:50 +0200 isync (0.9.2-3) unstable; urgency=low * Bump build-dependency from libdb4.0-dev to libdb4.2-dev, thanks to Andreas Jochens. (Closes: #280268) -- Nicolas Boullis Tue, 9 Nov 2004 18:21:12 +0100 isync (0.9.2-2) unstable; urgency=low * Add german debconf templates translation, thanks to Erik Schanze. (Closes: #267675) -- Nicolas Boullis Tue, 24 Aug 2004 00:32:32 +0200 isync (0.9.2-1) unstable; urgency=low * New upstream release. - Password prompt now includes the mailbox/server. (Closes: #92893) * Backported from CVS: - A few prinf converted to info (disabled with -q). - A few other printf converted to warn (disabled with -q -q) to be able to disable the warning when SSL is not available. (Closes: #228086) - Update the manpage accordingly (about -q). - Improve the manpage (about using isync with mutt). * Add Theodore Y. Ts'o as a co-maintainter. -- Nicolas Boullis Tue, 13 Apr 2004 02:12:42 +0200 isync (0.9.1-4) unstable; urgency=low * The "Why do I keep adding such stupid bugs?" release. * Remove the extra parenthesis that caused UID FETCH syntax errors, thanks to Niels den Otter for pointing the bug and giving the solution. (Closes: #224803) * Use configure's --build and --host options to prevent wrong optimizations (such as building for sparc64 rather than for sparc). -- Nicolas Boullis Wed, 7 Jan 2004 01:06:53 +0100 isync (0.9.1-3) unstable; urgency=low * Do not segfault when using both tunneled end non-tunneled connections, thanks to Nik A. Melchior for reporting and for his patch. (Closes: #220667) * Save uid of messages when interrupted, thanks to Theodore Y. Ts'o for reporting and for his patch. (Closes: #220346) * Do not get the sizes of the messages if unneeded (if MaxSize=0). -- Nicolas Boullis Thu, 18 Dec 2003 00:55:04 +0100 isync (0.9.1-2) unstable; urgency=low * Add french debconf templates translation, thanks to Christian Perrier. (Closes: #218118) -- Nicolas Boullis Mon, 3 Nov 2003 18:50:56 +0100 isync (0.9.1-1) unstable; urgency=low * New maintainer. (Closes: #180050) * New upstream release. - With the new option -R, isync is now able to create non-existent remote mailboxes. (Closes: #170388) * Update debian/copyright to match the current copyright: - Add Oswald Buddenhagen as copyright owner. - Add special exception for OpenSSL. * Add support for noopt in $DEB_BUILD_OPTIONS in debian/rules. * Switch to po-debconf. * Remove sample.isyncrc from debian/docs: no need to have it both as a doc and as an example. * Move package from section non-US/main (?) to mail. (Closes: #154216) * Update versionned build-dependency on debhelper to >= 4.1.16. * Bump Standards-Version to 3.6.1. (No change required.) -- Nicolas Boullis Tue, 14 Oct 2003 22:02:20 +0200 isync (0.8-4) unstable; urgency=low * Orphaned the package, as I no longer use it. -- Joey Hess Thu, 6 Feb 2003 15:46:38 -0500 isync (0.8-3) unstable; urgency=low * New upstream maintainer; updated copyright file web site address, and watch file. NB: new upstream has not made any new releases yet. -- Joey Hess Sat, 1 Feb 2003 16:03:49 -0500 isync (0.8-2) unstable; urgency=low * Only reset debconf question if user chooses to abort upgrade. Closes: #167363 * Don't open lock files O_EXCL. As seen in upstream cvs. * Description and build-deps updates. * Added README.Debian with notes on mutt integration. -- Joey Hess Fri, 1 Nov 2002 18:02:44 -0500 isync (0.8-1) unstable; urgency=low * New upstream release. Closes: #134080 **WARNING** You need to remove all the messages in your local folder if you were previously using another version of isync or else you will end up with duplicate messages on your IMAP server. * Has better support for uploading locally added messages. Closes: #120272 * Added a debconf queston with some info about this that lets you abort the upgrade. * Added NEWS.Debian with same info. * New maintainer. * Removed upstream debianization stuff. * Updated copyright file. * Updated to current policy throughout. * Added uscan watch file. * Updated build-deps. * Now that isync needs berkeley databases, go with db4, so I don't have to transition from db3 later. * Fix fd leak (forgot to close tmp dir in maildir). Closes: #150762 -- Joey Hess Tue, 29 Oct 2002 17:02:14 -0500 isync (0.7-1) unstable; urgency=low * New upstream version (Closes: #121312, #92051). * Rumors say this might fix bugs #102255 and #120272, but I have no test setup right now, so I'm leaving them open. * Updated standards-version. -- Tommi Virtanen Sat, 5 Jan 2002 16:13:35 +0200 isync (0.5-1) unstable; urgency=low * New upstream version (Closes: #98642). * Install sample.isyncrc too (Closes: #90464). -- Tommi Virtanen Sat, 23 Jun 2001 01:19:07 +0300 isync (0.4-1) unstable; urgency=low * Initial Release. -- Tommi Virtanen Sat, 10 Mar 2001 18:43:35 +0200 isync-1.4.4/debian/watch0000644000175000001440000000006314006611550012032 00000000000000version=3 http://sf.net/isync/ isync-(.*)\.tar\.gz isync-1.4.4/debian/README.Debian0000644000175000001440000000120214006611550013036 00000000000000A note from isync's web site: isync can be integrated into Mutt fairly easily with a few hooks: folder-hook ~A bind index $ folder-hook +maildir 'macro index $ "!mbsync the_channel:maildir\n"' where the_channel is the Channel used to sync this mailbox, and maildir is the name of the local mailbox itself. This works well so long as you are not modifying the IMAP mailbox outside of Mutt. However, if you are using another mail program simultaneously, Mutt will have the wrong idea of the local mailbox flags and messages will start disappearing from its index display (don't worry, they are still on disk). isync-1.4.4/debian/copyright0000644000175000001440000000242014006611550012733 00000000000000Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: isync Source: http://isync.sourceforge.net Files: * Copyright: 2000-2002, Michael R. Elkins 2002-2017, Oswald Buddenhagen 2004, Theodore Y. Ts'o License: GPL-2+ Files: debian/* Copyright: 2013, Alessandro Ghedini License: GPL-2+ License: GPL-2+ This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. . This package is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. . You should have received a copy of the GNU General Public License along with this program. If not, see . . As a special exception, mbsync may be linked with the OpenSSL library, despite that library's more restrictive license. . On Debian systems, the complete text of the GNU General Public License version 2 can be found in "/usr/share/common-licenses/GPL-2". isync-1.4.4/src/0000755000175000001440000000000014152374120010430 500000000000000isync-1.4.4/src/driver.c0000644000175000001440000000453314006611550012013 00000000000000/* * mbsync - mailbox synchronizer * Copyright (C) 2000-2002 Michael R. Elkins * Copyright (C) 2002-2006,2010-2012 Oswald Buddenhagen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * As a special exception, mbsync may be linked with the OpenSSL library, * despite that library's more restrictive license. */ #include "driver.h" #include #include driver_t *drivers[N_DRIVERS] = { &maildir_driver, &imap_driver }; uint count_generic_messages( message_t *msgs ) { uint count = 0; for (; msgs; msgs = msgs->next) count++; return count; } void free_generic_messages( message_t *msgs ) { message_t *tmsg; for (; msgs; msgs = tmsg) { tmsg = msgs->next; free( msgs->msgid ); free( msgs ); } } void parse_generic_store( store_conf_t *store, conffile_t *cfg, const char *type ) { if (!strcasecmp( "Trash", cfg->cmd )) { store->trash = nfstrdup( cfg->val ); } else if (!strcasecmp( "TrashRemoteNew", cfg->cmd )) { store->trash_remote_new = parse_bool( cfg ); } else if (!strcasecmp( "TrashNewOnly", cfg->cmd )) { store->trash_only_new = parse_bool( cfg ); } else if (!strcasecmp( "MaxSize", cfg->cmd )) { store->max_size = parse_size( cfg ); } else if (!strcasecmp( "MapInbox", cfg->cmd )) { store->map_inbox = nfstrdup( cfg->val ); } else if (!strcasecmp( "Flatten", cfg->cmd )) { const char *p; for (p = cfg->val; *p; p++) { if (*p == '/') { error( "%s:%d: flattened hierarchy delimiter cannot contain the canonical delimiter '/'\n", cfg->file, cfg->line ); cfg->err = 1; return; } } store->flat_delim = nfstrdup( cfg->val ); } else { error( "%s:%d: keyword '%s' is not recognized in %s sections\n", cfg->file, cfg->line, cfg->cmd, type ); cfg->err = 1; } } isync-1.4.4/src/main.c0000644000175000001440000007051314152373720011453 00000000000000/* * mbsync - mailbox synchronizer * Copyright (C) 2000-2002 Michael R. Elkins * Copyright (C) 2002-2006,2010-2017 Oswald Buddenhagen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * As a special exception, mbsync may be linked with the OpenSSL library, * despite that library's more restrictive license. */ #include "sync.h" #include #include #include #include #include #include #include #include #ifdef __linux__ # include #endif int DFlags; int JLimit; int UseFSync = 1; #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) || defined(__CYGWIN__) char FieldDelimiter = ';'; #else char FieldDelimiter = ':'; #endif int Pid; /* for maildir and imap */ char Hostname[256]; /* for maildir */ const char *Home; /* for config */ uint BufferLimit = 10 * 1024 * 1024; static int chans_total, chans_done; static int boxes_total, boxes_done; int new_total[2], new_done[2]; int flags_total[2], flags_done[2]; int trash_total[2], trash_done[2]; static void ATTR_NORETURN version( void ) { puts( PACKAGE " " VERSION ); exit( 0 ); } static void ATTR_NORETURN usage( int code ) { fputs( PACKAGE " " VERSION " - mailbox synchronizer\n" "Copyright (C) 2000-2002 Michael R. Elkins \n" "Copyright (C) 2002-2006,2008,2010-2017 Oswald Buddenhagen \n" "Copyright (C) 2004 Theodore Ts'o \n" "usage:\n" " " EXE " [flags] {{channel[:box,...]|group} ...|-a}\n" " -a, --all operate on all defined channels\n" " -l, --list list mailboxes instead of syncing them\n" " -n, --new propagate new messages\n" " -d, --delete propagate message deletions\n" " -f, --flags propagate message flag changes\n" " -N, --renew propagate previously not propagated new messages\n" " -L, --pull propagate from far to near side\n" " -H, --push propagate from near to far side\n" " -C, --create propagate creations of mailboxes\n" " -R, --remove propagate deletions of mailboxes\n" " -X, --expunge expunge deleted messages\n" " -c, --config CONFIG read an alternate config file (default: ~/." EXE "rc)\n" " -D, --debug debugging modes (see manual)\n" " -V, --verbose display what is happening\n" " -q, --quiet don't display progress counters\n" " -v, --version display version\n" " -h, --help display this help message\n" "\nIf neither --pull nor --push are specified, both are active.\n" "If neither --new, --delete, --flags nor --renew are specified, all are active.\n" "Direction and operation can be concatenated like --pull-new, etc.\n" "--create, --remove, and --expunge can be suffixed with -far/-near.\n" "See the man page for details.\n" "\nSupported mailbox formats are: IMAP4rev1, Maildir\n" "\nCompile time options:\n" #ifdef HAVE_LIBSSL " +HAVE_LIBSSL" #else " -HAVE_LIBSSL" #endif #ifdef HAVE_LIBSASL " +HAVE_LIBSASL" #else " -HAVE_LIBSASL" #endif #ifdef HAVE_LIBZ " +HAVE_LIBZ" #else " -HAVE_LIBZ" #endif #ifdef USE_DB " +USE_DB" #else " -USE_DB" #endif #ifdef HAVE_IPV6 " +HAVE_IPV6\n" #else " -HAVE_IPV6\n" #endif , code ? stderr : stdout ); exit( code ); } static void ATTR_PRINTFLIKE(1, 2) debug( const char *msg, ... ) { va_list va; va_start( va, msg ); vdebug( DEBUG_MAIN, msg, va ); va_end( va ); } #ifdef __linux__ static void ATTR_NORETURN crashHandler( int n ) { int dpid; char pbuf[10], pabuf[20]; close( 0 ); open( "/dev/tty", O_RDWR ); dup2( 0, 1 ); dup2( 0, 2 ); error( "*** " EXE " caught signal %d. Starting debugger ...\n", n ); #ifdef PR_SET_PTRACER int pip[2]; if (pipe( pip ) < 0) { perror( "pipe()" ); exit( 3 ); } #endif switch ((dpid = fork())) { case -1: perror( "fork()" ); break; case 0: #ifdef PR_SET_PTRACER close( pip[1] ); read( pip[0], pbuf, 1 ); close( pip[0] ); #endif sprintf( pbuf, "%d", Pid ); sprintf( pabuf, "/proc/%d/exe", Pid ); execlp( "gdb", "gdb", pabuf, pbuf, (char *)0 ); perror( "execlp()" ); _exit( 1 ); default: #ifdef PR_SET_PTRACER prctl( PR_SET_PTRACER, (ulong)dpid ); close( pip[1] ); close( pip[0] ); #endif waitpid( dpid, NULL, 0 ); break; } exit( 3 ); } #endif void stats( void ) { char buf[3][64]; char *cs; int t, l, ll, cls; static int cols = -1; if (!(DFlags & PROGRESS)) return; if (cols < 0 && (!(cs = getenv( "COLUMNS" )) || !(cols = atoi( cs )))) cols = 80; ll = sprintf( buf[2], "C: %d/%d B: %d/%d", chans_done, chans_total, boxes_done, boxes_total ); cls = (cols - ll - 10) / 2; for (t = 0; t < 2; t++) { l = sprintf( buf[t], "+%d/%d *%d/%d #%d/%d", new_done[t], new_total[t], flags_done[t], flags_total[t], trash_done[t], trash_total[t] ); if (l > cls) buf[t][cls - 1] = '~'; } progress( "\r%s F: %.*s N: %.*s", buf[2], cls, buf[0], cls, buf[1] ); } static int matches( const char *t, const char *p ) { for (;;) { if (!*p) return !*t; if (*p == '*') { p++; do { if (matches( t, p )) return 1; } while (*t++); return 0; } else if (*p == '%') { p++; do { if (*t == '/') return 0; if (matches( t, p )) return 1; } while (*t++); return 0; } else { if (*p != *t) return 0; p++, t++; } } } static int is_inbox( const char *name ) { return starts_with( name, -1, "INBOX", 5 ) && (!name[5] || name[5] == '/'); } static int cmp_box_names( const void *a, const void *b ) { const char *as = *(const char * const *)a; const char *bs = *(const char * const *)b; int ai = is_inbox( as ); int bi = is_inbox( bs ); int di = bi - ai; if (di) return di; return strcmp( as, bs ); } static char ** filter_boxes( string_list_t *boxes, const char *prefix, string_list_t *patterns ) { string_list_t *cpat; char **boxarr = NULL; const char *ps; uint not, fnot, pfxl, num = 0, rnum = 0; pfxl = prefix ? strlen( prefix ) : 0; for (; boxes; boxes = boxes->next) { if (!starts_with( boxes->string, -1, prefix, pfxl )) continue; fnot = 1; for (cpat = patterns; cpat; cpat = cpat->next) { ps = cpat->string; if (*ps == '!') { ps++; not = 1; } else not = 0; if (matches( boxes->string + pfxl, ps )) { fnot = not; break; } } if (!fnot) { if (num + 1 >= rnum) boxarr = nfrealloc( boxarr, (rnum = (rnum + 10) * 2) * sizeof(*boxarr) ); boxarr[num++] = nfstrdup( boxes->string + pfxl ); boxarr[num] = NULL; } } qsort( boxarr, num, sizeof(*boxarr), cmp_box_names ); return boxarr; } static void merge_actions( channel_conf_t *chan, int ops[], int have, int mask, int def ) { if (ops[F] & have) { chan->ops[F] &= ~mask; chan->ops[F] |= ops[F] & mask; chan->ops[N] &= ~mask; chan->ops[N] |= ops[N] & mask; } else if (!(chan->ops[F] & have)) { if (global_conf.ops[F] & have) { chan->ops[F] |= global_conf.ops[F] & mask; chan->ops[N] |= global_conf.ops[N] & mask; } else { chan->ops[F] |= def; chan->ops[N] |= def; } } } typedef struct box_ent { struct box_ent *next; char *name; int present[2]; } box_ent_t; typedef struct chan_ent { struct chan_ent *next; channel_conf_t *conf; box_ent_t *boxes; char boxlist; } chan_ent_t; static chan_ent_t * add_channel( chan_ent_t ***chanapp, channel_conf_t *chan, int ops[] ) { chan_ent_t *ce = nfcalloc( sizeof(*ce) ); ce->conf = chan; merge_actions( chan, ops, XOP_HAVE_TYPE, OP_MASK_TYPE, OP_MASK_TYPE ); merge_actions( chan, ops, XOP_HAVE_CREATE, OP_CREATE, 0 ); merge_actions( chan, ops, XOP_HAVE_REMOVE, OP_REMOVE, 0 ); merge_actions( chan, ops, XOP_HAVE_EXPUNGE, OP_EXPUNGE, 0 ); **chanapp = ce; *chanapp = &ce->next; chans_total++; return ce; } static chan_ent_t * add_named_channel( chan_ent_t ***chanapp, char *channame, int ops[] ) { channel_conf_t *chan; chan_ent_t *ce; box_ent_t *boxes = NULL, **mboxapp = &boxes, *mbox; char *boxp, *nboxp; size_t boxl; char boxlist = 0; if ((boxp = strchr( channame, ':' ))) *boxp++ = 0; for (chan = channels; chan; chan = chan->next) if (!strcmp( chan->name, channame )) goto gotchan; error( "No channel or group named '%s' defined.\n", channame ); return NULL; gotchan: if (boxp) { if (!chan->patterns) { error( "Cannot override mailbox in channel '%s' - no Patterns.\n", channame ); return NULL; } boxlist = 1; do { nboxp = strpbrk( boxp, ",\n" ); if (nboxp) { boxl = (size_t)(nboxp - boxp); *nboxp++ = 0; } else { boxl = strlen( boxp ); } mbox = nfmalloc( sizeof(*mbox) ); if (boxl) mbox->name = nfstrndup( boxp, boxl ); else mbox->name = nfstrndup( "INBOX", 5 ); mbox->present[F] = mbox->present[N] = BOX_POSSIBLE; mbox->next = NULL; *mboxapp = mbox; mboxapp = &mbox->next; boxes_total++; boxp = nboxp; } while (boxp); } else { if (!chan->patterns) boxes_total++; } ce = add_channel( chanapp, chan, ops ); ce->boxes = boxes; ce->boxlist = boxlist; return ce; } typedef struct { int t[2]; channel_conf_t *chan; driver_t *drv[2]; store_t *ctx[2]; chan_ent_t *chanptr; box_ent_t *boxptr; string_list_t *boxes[2]; char *names[2]; int ret, all, list, state[2]; char done, skip, cben; } main_vars_t; #define AUX &mvars->t[t] #define MVARS(aux) \ int t = *(int *)aux; \ main_vars_t *mvars = (main_vars_t *)(((char *)(&((int *)aux)[-t])) - offsetof(main_vars_t, t)); #define E_START 0 #define E_OPEN 1 #define E_SYNC 2 static void sync_chans( main_vars_t *mvars, int ent ); int main( int argc, char **argv ) { main_vars_t mvars[1]; chan_ent_t *chans = NULL, **chanapp = &chans; group_conf_t *group; channel_conf_t *chan; string_list_t *channame; char *config = NULL, *opt, *ochar; int oind, cops = 0, op, ops[2] = { 0, 0 }, ms_warn = 0; tzset(); gethostname( Hostname, sizeof(Hostname) ); if ((ochar = strchr( Hostname, '.' ))) *ochar = 0; Pid = getpid(); if (!(Home = getenv("HOME"))) { fputs( "Fatal: $HOME not set\n", stderr ); return 1; } arc4_init(); memset( mvars, 0, sizeof(*mvars) ); mvars->t[1] = 1; for (oind = 1, ochar = NULL; ; ) { if (!ochar || !*ochar) { if (oind >= argc) break; if (argv[oind][0] != '-') break; if (argv[oind][1] == '-') { opt = argv[oind++] + 2; if (!*opt) break; if (!strcmp( opt, "config" )) { if (oind >= argc) { error( "--config requires an argument.\n" ); return 1; } config = argv[oind++]; } else if (starts_with( opt, -1, "config=", 7 )) config = opt + 7; else if (!strcmp( opt, "all" )) mvars->all = 1; else if (!strcmp( opt, "list" )) mvars->list = 1; else if (!strcmp( opt, "help" )) usage( 0 ); else if (!strcmp( opt, "version" )) version(); else if (!strcmp( opt, "quiet" )) { if (DFlags & QUIET) DFlags |= VERYQUIET; else DFlags |= QUIET; } else if (!strcmp( opt, "verbose" )) { DFlags |= VERBOSE; } else if (starts_with( opt, -1, "debug", 5 )) { opt += 5; if (!*opt) op = VERBOSE | DEBUG_ALL; else if (!strcmp( opt, "-crash" )) op = DEBUG_CRASH; else if (!strcmp( opt, "-driver" )) op = VERBOSE | DEBUG_DRV; else if (!strcmp( opt, "-driver-all" )) op = VERBOSE | DEBUG_DRV | DEBUG_DRV_ALL; else if (!strcmp( opt, "-maildir" )) op = VERBOSE | DEBUG_MAILDIR; else if (!strcmp( opt, "-main" )) op = VERBOSE | DEBUG_MAIN; else if (!strcmp( opt, "-net" )) op = VERBOSE | DEBUG_NET; else if (!strcmp( opt, "-net-all" )) op = VERBOSE | DEBUG_NET | DEBUG_NET_ALL; else if (!strcmp( opt, "-sync" )) op = VERBOSE | DEBUG_SYNC; else goto badopt; DFlags |= op; } else if (!strcmp( opt, "pull" )) cops |= XOP_PULL, ops[F] |= XOP_HAVE_TYPE; else if (!strcmp( opt, "push" )) cops |= XOP_PUSH, ops[F] |= XOP_HAVE_TYPE; else if (starts_with( opt, -1, "create", 6 )) { opt += 6; op = OP_CREATE|XOP_HAVE_CREATE; lcop: if (!*opt) cops |= op; else if (!strcmp( opt, "-far" )) ops[F] |= op; else if (!strcmp( opt, "-master" )) // Pre-1.4 legacy ops[F] |= op, ms_warn = 1; else if (!strcmp( opt, "-near" )) ops[N] |= op; else if (!strcmp( opt, "-slave" )) // Pre-1.4 legacy ops[N] |= op, ms_warn = 1; else goto badopt; ops[F] |= op & (XOP_HAVE_CREATE|XOP_HAVE_REMOVE|XOP_HAVE_EXPUNGE); } else if (starts_with( opt, -1, "remove", 6 )) { opt += 6; op = OP_REMOVE|XOP_HAVE_REMOVE; goto lcop; } else if (starts_with( opt, -1, "expunge", 7 )) { opt += 7; op = OP_EXPUNGE|XOP_HAVE_EXPUNGE; goto lcop; } else if (!strcmp( opt, "no-expunge" )) ops[F] |= XOP_HAVE_EXPUNGE; else if (!strcmp( opt, "no-create" )) ops[F] |= XOP_HAVE_CREATE; else if (!strcmp( opt, "no-remove" )) ops[F] |= XOP_HAVE_REMOVE; else if (!strcmp( opt, "full" )) ops[F] |= XOP_HAVE_TYPE|XOP_PULL|XOP_PUSH; else if (!strcmp( opt, "noop" )) ops[F] |= XOP_HAVE_TYPE; else if (starts_with( opt, -1, "pull", 4 )) { op = XOP_PULL; lcac: opt += 4; if (!*opt) cops |= op; else if (*opt == '-') { opt++; goto rlcac; } else goto badopt; } else if (starts_with( opt, -1, "push", 4 )) { op = XOP_PUSH; goto lcac; } else { op = 0; rlcac: if (!strcmp( opt, "new" )) op |= OP_NEW; else if (!strcmp( opt, "renew" )) op |= OP_RENEW; else if (!strcmp( opt, "delete" )) op |= OP_DELETE; else if (!strcmp( opt, "flags" )) op |= OP_FLAGS; else { badopt: error( "Unknown option '%s'\n", argv[oind - 1] ); return 1; } switch (op & XOP_MASK_DIR) { case XOP_PULL: ops[N] |= op & OP_MASK_TYPE; break; case XOP_PUSH: ops[F] |= op & OP_MASK_TYPE; break; default: cops |= op; break; } ops[F] |= XOP_HAVE_TYPE; } continue; } ochar = argv[oind++] + 1; if (!*ochar) { error( "Invalid option '-'\n" ); return 1; } } switch (*ochar++) { case 'a': mvars->all = 1; break; case 'l': mvars->list = 1; break; case 'c': if (oind >= argc) { error( "-c requires an argument.\n" ); return 1; } config = argv[oind++]; break; case 'C': op = OP_CREATE|XOP_HAVE_CREATE; cop: if (*ochar == 'f') ops[F] |= op, ochar++; else if (*ochar == 'm') // Pre-1.4 legacy ops[F] |= op, ms_warn = 1, ochar++; else if (*ochar == 'n') ops[N] |= op, ochar++; else if (*ochar == 's') // Pre-1.4 legacy ops[N] |= op, ms_warn = 1, ochar++; else if (*ochar == '-') ochar++; else cops |= op; ops[F] |= op & (XOP_HAVE_CREATE|XOP_HAVE_REMOVE|XOP_HAVE_EXPUNGE); break; case 'R': op = OP_REMOVE|XOP_HAVE_REMOVE; goto cop; case 'X': op = OP_EXPUNGE|XOP_HAVE_EXPUNGE; goto cop; case 'F': cops |= XOP_PULL|XOP_PUSH; FALLTHROUGH case '0': ops[F] |= XOP_HAVE_TYPE; break; case 'n': case 'd': case 'f': case 'N': --ochar; op = 0; cac: for (;; ochar++) { if (*ochar == 'n') op |= OP_NEW; else if (*ochar == 'd') op |= OP_DELETE; else if (*ochar == 'f') op |= OP_FLAGS; else if (*ochar == 'N') op |= OP_RENEW; else break; } if (op & OP_MASK_TYPE) switch (op & XOP_MASK_DIR) { case XOP_PULL: ops[N] |= op & OP_MASK_TYPE; break; case XOP_PUSH: ops[F] |= op & OP_MASK_TYPE; break; default: cops |= op; break; } else cops |= op; ops[F] |= XOP_HAVE_TYPE; break; case 'L': op = XOP_PULL; goto cac; case 'H': op = XOP_PUSH; goto cac; case 'q': if (DFlags & QUIET) DFlags |= VERYQUIET; else DFlags |= QUIET; break; case 'V': DFlags |= VERBOSE; break; case 'D': for (op = 0; *ochar; ochar++) { switch (*ochar) { case 'C': op |= DEBUG_CRASH; break; case 'd': op |= DEBUG_DRV | VERBOSE; break; case 'D': op |= DEBUG_DRV | DEBUG_DRV_ALL | VERBOSE; break; case 'm': op |= DEBUG_MAILDIR | VERBOSE; break; case 'M': op |= DEBUG_MAIN | VERBOSE; break; case 'n': op |= DEBUG_NET | VERBOSE; break; case 'N': op |= DEBUG_NET | DEBUG_NET_ALL | VERBOSE; break; case 's': op |= DEBUG_SYNC | VERBOSE; break; default: error( "Unknown -D flag '%c'\n", *ochar ); return 1; } } if (!op) op = DEBUG_ALL | VERBOSE; DFlags |= op; break; case 'T': for (; *ochar; ) { switch (*ochar++) { case 'a': DFlags |= FORCEASYNC; break; case 'j': DFlags |= KEEPJOURNAL; JLimit = strtol( ochar, &ochar, 10 ); break; case 'z': DFlags |= ZERODELAY; break; default: error( "Unknown -T flag '%c'\n", *(ochar - 1) ); return 1; } } break; case 'v': version(); case 'h': usage( 0 ); default: error( "Unknown option '-%c'\n", *(ochar - 1) ); return 1; } } if (ms_warn) warn( "Notice: -master/-slave/m/s suffixes are deprecated; use -far/-near/f/n instead.\n" ); if (!(DFlags & (QUIET | DEBUG_ALL)) && isatty( 1 )) DFlags |= PROGRESS; #ifdef __linux__ if (DFlags & DEBUG_CRASH) { signal( SIGSEGV, crashHandler ); signal( SIGBUS, crashHandler ); signal( SIGILL, crashHandler ); } #endif if (merge_ops( cops, ops )) return 1; if (load_config( config )) return 1; if (!channels) { fputs( "No channels defined. Try 'man " EXE "'\n", stderr ); return 1; } if (mvars->all) { for (chan = channels; chan; chan = chan->next) { add_channel( &chanapp, chan, ops ); if (!chan->patterns) boxes_total++; } } else { for (; argv[oind]; oind++) { for (group = groups; group; group = group->next) { if (!strcmp( group->name, argv[oind] )) { for (channame = group->channels; channame; channame = channame->next) if (!add_named_channel( &chanapp, channame->string, ops )) mvars->ret = 1; goto gotgrp; } } if (!add_named_channel( &chanapp, argv[oind], ops )) mvars->ret = 1; gotgrp: ; } } if (!chans) { fputs( "No channel specified. Try '" EXE " -h'\n", stderr ); return 1; } mvars->chanptr = chans; if (!mvars->list) stats(); mvars->cben = 1; sync_chans( mvars, E_START ); main_loop(); if (!mvars->list) flushn(); return mvars->ret; } #define ST_FRESH 0 #define ST_CONNECTED 1 #define ST_OPEN 2 #define ST_CANCELING 3 #define ST_CLOSED 4 static void cancel_prep_done( void *aux ) { MVARS(aux) mvars->drv[t]->free_store( mvars->ctx[t] ); mvars->state[t] = ST_CLOSED; sync_chans( mvars, E_OPEN ); } static void store_bad( void *aux ) { MVARS(aux) mvars->drv[t]->cancel_store( mvars->ctx[t] ); mvars->state[t] = ST_CLOSED; mvars->ret = mvars->skip = 1; sync_chans( mvars, E_OPEN ); } static void store_connected( int sts, void *aux ); static void store_listed( int sts, string_list_t *boxes, void *aux ); static int sync_listed_boxes( main_vars_t *mvars, box_ent_t *mbox ); static void done_sync_2_dyn( int sts, void *aux ); static void done_sync( int sts, void *aux ); #define nz(a,b) ((a)?(a):(b)) static void sync_chans( main_vars_t *mvars, int ent ) { box_ent_t *mbox, *nmbox, **mboxapp; char **boxes[2]; const char *labels[2]; int t, mb, sb, cmp; if (!mvars->cben) return; switch (ent) { case E_OPEN: goto opened; case E_SYNC: goto syncone; } do { mvars->chan = mvars->chanptr->conf; info( "Channel %s\n", mvars->chan->name ); mvars->skip = mvars->cben = 0; for (t = 0; t < 2; t++) { int st = mvars->chan->stores[t]->driver->get_fail_state( mvars->chan->stores[t] ); if (st != FAIL_TEMP) { info( "Skipping due to %sfailed %s store %s.\n", (st == FAIL_WAIT) ? "temporarily " : "", str_fn[t], mvars->chan->stores[t]->name ); mvars->skip = 1; } } if (mvars->skip) goto next2; mvars->state[F] = mvars->state[N] = ST_FRESH; uint dcaps[2]; for (t = 0; t < 2; t++) { mvars->drv[t] = mvars->chan->stores[t]->driver; dcaps[t] = mvars->drv[t]->get_caps( NULL ); } if ((DFlags & DEBUG_DRV) || (dcaps[F] & dcaps[N] & DRV_VERBOSE)) labels[F] = "F: ", labels[N] = "N: "; else labels[F] = labels[N] = ""; for (t = 0; t < 2; t++) { store_t *ctx = mvars->drv[t]->alloc_store( mvars->chan->stores[t], labels[t] ); if ((DFlags & DEBUG_DRV) || ((DFlags & FORCEASYNC) && !(dcaps[t] & DRV_ASYNC))) { mvars->drv[t] = &proxy_driver; ctx = proxy_alloc_store( ctx, labels[t] ); } mvars->ctx[t] = ctx; mvars->drv[t]->set_bad_callback( ctx, store_bad, AUX ); } for (t = 0; ; t++) { info( "Opening %s store %s...\n", str_fn[t], mvars->chan->stores[t]->name ); mvars->drv[t]->connect_store( mvars->ctx[t], store_connected, AUX ); if (t || mvars->skip) break; } mvars->cben = 1; opened: if (mvars->skip) goto next; if (mvars->state[F] != ST_OPEN || mvars->state[N] != ST_OPEN) return; if (!mvars->chanptr->boxlist && mvars->chan->patterns) { mvars->chanptr->boxlist = 2; boxes[F] = filter_boxes( mvars->boxes[F], mvars->chan->boxes[F], mvars->chan->patterns ); boxes[N] = filter_boxes( mvars->boxes[N], mvars->chan->boxes[N], mvars->chan->patterns ); mboxapp = &mvars->chanptr->boxes; for (mb = sb = 0; ; ) { char *mname = boxes[F] ? boxes[F][mb] : NULL; char *sname = boxes[N] ? boxes[N][sb] : NULL; if (!mname && !sname) break; mbox = nfmalloc( sizeof(*mbox) ); if (!(cmp = !mname - !sname) && !(cmp = cmp_box_names( &mname, &sname ))) { mbox->name = mname; free( sname ); mbox->present[F] = mbox->present[N] = BOX_PRESENT; mb++; sb++; } else if (cmp < 0) { mbox->name = mname; mbox->present[F] = BOX_PRESENT; mbox->present[N] = (!mb && !strcmp( mbox->name, "INBOX" )) ? BOX_PRESENT : BOX_ABSENT; mb++; } else { mbox->name = sname; mbox->present[F] = (!sb && !strcmp( mbox->name, "INBOX" )) ? BOX_PRESENT : BOX_ABSENT; mbox->present[N] = BOX_PRESENT; sb++; } mbox->next = NULL; *mboxapp = mbox; mboxapp = &mbox->next; boxes_total++; } free( boxes[F] ); free( boxes[N] ); if (!mvars->list) stats(); } mvars->boxptr = mvars->chanptr->boxes; if (mvars->list && chans_total > 1) printf( "%s:\n", mvars->chan->name ); syncml: mvars->done = mvars->cben = 0; if (mvars->chanptr->boxlist) { while ((mbox = mvars->boxptr)) { mvars->boxptr = mbox->next; if (sync_listed_boxes( mvars, mbox )) goto syncw; } } else { if (!mvars->list) { int present[] = { BOX_POSSIBLE, BOX_POSSIBLE }; sync_boxes( mvars->ctx, mvars->chan->boxes, present, mvars->chan, done_sync, mvars ); mvars->skip = 1; syncw: mvars->cben = 1; if (!mvars->done) return; syncone: if (!mvars->skip) goto syncml; } else printf( "%s <=> %s\n", nz( mvars->chan->boxes[F], "INBOX" ), nz( mvars->chan->boxes[N], "INBOX" ) ); } next: mvars->cben = 0; for (t = 0; t < 2; t++) { free_string_list( mvars->boxes[t] ); mvars->boxes[t] = NULL; if (mvars->state[t] == ST_FRESH) { /* An unconnected store may be only cancelled. */ mvars->state[t] = ST_CLOSED; mvars->drv[t]->cancel_store( mvars->ctx[t] ); } else if (mvars->state[t] == ST_CONNECTED || mvars->state[t] == ST_OPEN) { mvars->state[t] = ST_CANCELING; mvars->drv[t]->cancel_cmds( mvars->ctx[t], cancel_prep_done, AUX ); } } mvars->cben = 1; if (mvars->state[F] != ST_CLOSED || mvars->state[N] != ST_CLOSED) { mvars->skip = 1; return; } if (mvars->chanptr->boxlist) { for (nmbox = mvars->chanptr->boxes; (mbox = nmbox); ) { nmbox = mbox->next; free( mbox->name ); free( mbox ); } mvars->chanptr->boxes = NULL; mvars->chanptr->boxlist = 0; } next2: if (!mvars->list) { chans_done++; stats(); } chan_ent_t *nchan = mvars->chanptr->next; free( mvars->chanptr ); mvars->chanptr = nchan; } while (mvars->chanptr); for (t = 0; t < N_DRIVERS; t++) drivers[t]->cleanup(); } static void store_connected( int sts, void *aux ) { MVARS(aux) string_list_t *cpat; int cflags; switch (sts) { case DRV_CANCELED: return; case DRV_OK: if (!mvars->skip && !mvars->chanptr->boxlist && mvars->chan->patterns) { for (cflags = 0, cpat = mvars->chan->patterns; cpat; cpat = cpat->next) { const char *pat = cpat->string; if (*pat != '!') { char buf[8]; int bufl = snprintf( buf, sizeof(buf), "%s%s", nz( mvars->chan->boxes[t], "" ), pat ); int flags = 0; /* Partial matches like "INB*" or even "*" are not considered, * except implicity when the INBOX lives under Path. */ if (starts_with( buf, bufl, "INBOX", 5 )) { char c = buf[5]; if (!c) { /* User really wants the INBOX. */ flags |= LIST_INBOX; } else if (c == '/') { /* Flattened sub-folders of INBOX actually end up in Path. */ if (mvars->ctx[t]->conf->flat_delim[0]) flags |= LIST_PATH; else flags |= LIST_INBOX; } else if (c == '*' || c == '%') { /* It can be both INBOX and Path, but don't require Path to be configured. */ flags |= LIST_INBOX | LIST_PATH_MAYBE; } else { /* It's definitely not the INBOX. */ flags |= LIST_PATH; } } else { flags |= LIST_PATH; } debug( "pattern '%s' (effective '%s'): %sPath, %sINBOX\n", pat, buf, (flags & LIST_PATH) ? "" : "no ", (flags & LIST_INBOX) ? "" : "no "); cflags |= flags; } } mvars->state[t] = ST_CONNECTED; mvars->drv[t]->list_store( mvars->ctx[t], cflags, store_listed, AUX ); return; } mvars->state[t] = ST_OPEN; break; default: mvars->ret = mvars->skip = 1; mvars->state[t] = ST_OPEN; break; } sync_chans( mvars, E_OPEN ); } static void store_listed( int sts, string_list_t *boxes, void *aux ) { MVARS(aux) string_list_t *box; switch (sts) { case DRV_CANCELED: return; case DRV_OK: for (box = boxes; box; box = box->next) { if (mvars->ctx[t]->conf->flat_delim[0]) { string_list_t *nbox; if (map_name( box->string, (char **)&nbox, offsetof(string_list_t, string), mvars->ctx[t]->conf->flat_delim, "/" ) < 0) { error( "Error: flattened mailbox name '%s' contains canonical hierarchy delimiter\n", box->string ); mvars->ret = mvars->skip = 1; } else { nbox->next = mvars->boxes[t]; mvars->boxes[t] = nbox; } } else { add_string_list( &mvars->boxes[t], box->string ); } } if (mvars->ctx[t]->conf->map_inbox) { debug( "adding mapped inbox to %s store: %s\n", str_fn[t], mvars->ctx[t]->conf->map_inbox ); add_string_list( &mvars->boxes[t], mvars->ctx[t]->conf->map_inbox ); } break; default: mvars->ret = mvars->skip = 1; break; } mvars->state[t] = ST_OPEN; sync_chans( mvars, E_OPEN ); } static int sync_listed_boxes( main_vars_t *mvars, box_ent_t *mbox ) { if (mvars->chan->boxes[F] || mvars->chan->boxes[N]) { const char *mpfx = nz( mvars->chan->boxes[F], "" ); const char *spfx = nz( mvars->chan->boxes[N], "" ); if (!mvars->list) { nfasprintf( &mvars->names[F], "%s%s", mpfx, mbox->name ); nfasprintf( &mvars->names[N], "%s%s", spfx, mbox->name ); sync_boxes( mvars->ctx, (const char * const *)mvars->names, mbox->present, mvars->chan, done_sync_2_dyn, mvars ); return 1; } printf( "%s%s <=> %s%s\n", mpfx, mbox->name, spfx, mbox->name ); } else { if (!mvars->list) { mvars->names[F] = mvars->names[N] = mbox->name; sync_boxes( mvars->ctx, (const char * const *)mvars->names, mbox->present, mvars->chan, done_sync, mvars ); return 1; } puts( mbox->name ); } return 0; } static void done_sync_2_dyn( int sts, void *aux ) { main_vars_t *mvars = (main_vars_t *)aux; free( mvars->names[F] ); free( mvars->names[N] ); done_sync( sts, aux ); } static void done_sync( int sts, void *aux ) { main_vars_t *mvars = (main_vars_t *)aux; mvars->done = 1; boxes_done++; stats(); if (sts) { mvars->ret = 1; if (sts & (SYNC_BAD(F) | SYNC_BAD(N))) { if (sts & SYNC_BAD(F)) mvars->state[F] = ST_CLOSED; if (sts & SYNC_BAD(N)) mvars->state[N] = ST_CLOSED; mvars->skip = 1; } } sync_chans( mvars, E_SYNC ); } isync-1.4.4/src/sync.h0000644000175000001440000000534414006611550011502 00000000000000/* * mbsync - mailbox synchronizer * Copyright (C) 2000-2002 Michael R. Elkins * Copyright (C) 2002-2006,2010-2012 Oswald Buddenhagen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * As a special exception, mbsync may be linked with the OpenSSL library, * despite that library's more restrictive license. */ #ifndef SYNC_H #define SYNC_H #include "driver.h" #define F 0 // far side #define N 1 // near side #define OP_NEW (1<<0) #define OP_RENEW (1<<1) #define OP_DELETE (1<<2) #define OP_FLAGS (1<<3) #define OP_MASK_TYPE (OP_NEW|OP_RENEW|OP_DELETE|OP_FLAGS) /* asserted in the target ops */ #define OP_EXPUNGE (1<<4) #define OP_CREATE (1<<5) #define OP_REMOVE (1<<6) #define XOP_PUSH (1<<8) #define XOP_PULL (1<<9) #define XOP_MASK_DIR (XOP_PUSH|XOP_PULL) #define XOP_HAVE_TYPE (1<<10) // The following must all have the same bit shift from the corresponding OP_* flags. #define XOP_HAVE_EXPUNGE (1<<11) #define XOP_HAVE_CREATE (1<<12) #define XOP_HAVE_REMOVE (1<<13) typedef struct channel_conf { struct channel_conf *next; const char *name; store_conf_t *stores[2]; const char *boxes[2]; char *sync_state; string_list_t *patterns; int ops[2]; int max_messages; // For near side only. signed char expire_unread; char use_internal_date; } channel_conf_t; typedef struct group_conf { struct group_conf *next; const char *name; string_list_t *channels; } group_conf_t; extern channel_conf_t global_conf; extern channel_conf_t *channels; extern group_conf_t *groups; extern const char *str_fn[2], *str_hl[2]; #define SYNC_OK 0 /* assumed to be 0 */ #define SYNC_FAIL 1 #define SYNC_BAD(fn) (4<<(fn)) #define SYNC_NOGOOD 16 /* internal */ #define SYNC_CANCELED 32 /* internal */ #define BOX_POSSIBLE -1 #define BOX_ABSENT 0 #define BOX_PRESENT 1 /* All passed pointers must stay alive until cb is called. */ void sync_boxes( store_t *ctx[], const char * const names[], int present[], channel_conf_t *chan, void (*cb)( int sts, void *aux ), void *aux ); #endif isync-1.4.4/src/drv_imap.c0000644000175000001440000031216614152373720012333 00000000000000/* * mbsync - mailbox synchronizer * Copyright (C) 2000-2002 Michael R. Elkins * Copyright (C) 2002-2006,2008,2010-2013 Oswald Buddenhagen * Copyright (C) 2004 Theodore Y. Ts'o * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * As a special exception, mbsync may be linked with the OpenSSL library, * despite that library's more restrictive license. */ #include "driver.h" #include "socket.h" #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_LIBSASL # include # include #endif #ifdef HAVE_MACOS_KEYCHAIN # include #endif #ifdef HAVE_LIBSSL enum { SSL_None, SSL_STARTTLS, SSL_IMAPS }; #endif typedef struct imap_server_conf { struct imap_server_conf *next; char *name; server_conf_t sconf; char *user; char *user_cmd; char *pass; char *pass_cmd; int max_in_progress; uint cap_mask; string_list_t *auth_mechs; #ifdef HAVE_LIBSSL char ssl_type; #endif #ifdef HAVE_MACOS_KEYCHAIN char use_keychain; #endif char failed; } imap_server_conf_t; typedef union imap_store_conf { store_conf_t gen; struct { STORE_CONF imap_server_conf_t *server; char *path; // Note: this may be modified after the delimiter is determined. char delimiter; char use_namespace; char use_lsub; }; } imap_store_conf_t; typedef union imap_message { message_t gen; struct { MESSAGE(union imap_message) // uint seq; will be needed when expunges are tracked }; } imap_message_t; #define NIL (void*)0x1 #define LIST (void*)0x2 typedef struct _list { struct _list *next, *child; char *val; uint len; } list_t; #define MAX_LIST_DEPTH 5 typedef union imap_store imap_store_t; typedef struct { list_t *head, **stack[MAX_LIST_DEPTH]; int (*callback)( imap_store_t *ctx, list_t *list, char *cmd ); int level, need_bytes; } parse_list_state_t; typedef struct imap_cmd imap_cmd_t; union imap_store { store_t gen; struct { STORE(union imap_store) const char *label; // foreign const char *name; char *prefix; uint ref_count; uint opts; enum { SST_BAD, SST_HALF, SST_GOOD } state; // The trash folder's existence is not confirmed yet enum { TrashUnknown, TrashChecking, TrashKnown } trashnc; // What kind of BODY-less FETCH response we're expecting enum { FetchNone, FetchMsgs, FetchUidNext } fetch_sts; uint got_namespace:1; uint has_forwarded:1; char delimiter[2]; // Hierarchy delimiter char *ns_prefix, ns_delimiter; // NAMESPACE info string_list_t *boxes; // _list results char listed; // was _list already run with these flags? // note that the message counts do _not_ reflect stats from msgs, // but mailbox totals. int total_msgs, recent_msgs; uint uidvalidity, uidnext; imap_message_t **msgapp, *msgs; // FETCH results uint caps; // CAPABILITY results string_list_t *auth_mechs; parse_list_state_t parse_list_sts; // Command queue imap_cmd_t *pending, **pending_append; imap_cmd_t *in_progress, **in_progress_append; imap_cmd_t *wait_check, **wait_check_append; int nexttag, num_in_progress, num_wait_check; uint buffer_mem; // Memory currently occupied by buffers in the queue // Used during sequential operations like connect enum { GreetingPending = 0, GreetingBad, GreetingOk, GreetingPreauth } greeting; int expectBYE; // LOGOUT is in progress int expectEOF; // received LOGOUT's OK or unsolicited BYE int canceling; // imap_cancel() is in progress union { void (*imap_open)( int sts, void *aux ); void (*imap_cancel)( void *aux ); } callbacks; void *callback_aux; #ifdef HAVE_LIBSASL sasl_conn_t *sasl; int sasl_cont; #endif void (*bad_callback)( void *aux ); void *bad_callback_aux; conn_t conn; // This is BIG, so put it last }; }; #define IMAP_CMD \ struct imap_cmd *next; \ char *cmd; \ int tag; \ \ struct { \ /* Will be called on each continuation request until it resets this pointer. \ * Needs to invoke bad_callback and return -1 on error, otherwise return 0. */ \ int (*cont)( imap_store_t *ctx, imap_cmd_t *cmd, const char *prompt ); \ void (*done)( imap_store_t *ctx, imap_cmd_t *cmd, int response ); \ char *data; \ uint data_len; \ uint uid; /* to identify fetch responses */ \ char high_prio; /* if command is queued, put it at the front of the queue. */ \ char wait_check; /* Don't report success until subsequent CHECK success. */ \ char to_trash; /* we are storing to trash, not current. */ \ char create; /* create the mailbox if we get an error which suggests so. */ \ char failok; /* Don't complain about NO response. */ \ } param; struct imap_cmd { IMAP_CMD }; #define IMAP_CMD_SIMPLE \ IMAP_CMD \ void (*callback)( int sts, void *aux ); \ void *callback_aux; typedef union { imap_cmd_t gen; struct { IMAP_CMD_SIMPLE }; } imap_cmd_simple_t; typedef union { imap_cmd_simple_t gen; struct { IMAP_CMD_SIMPLE msg_data_t *msg_data; }; } imap_cmd_fetch_msg_t; typedef union { imap_cmd_t gen; struct { IMAP_CMD void (*callback)( int sts, uint uid, void *aux ); void *callback_aux; }; } imap_cmd_out_uid_t; typedef union { imap_cmd_t gen; struct { IMAP_CMD void (*callback)( int sts, message_t *msgs, void *aux ); void *callback_aux; imap_message_t **out_msgs; uint uid; }; } imap_cmd_find_new_t; #define IMAP_CMD_REFCOUNTED_STATE \ uint ref_count; \ int ret_val; typedef struct { IMAP_CMD_REFCOUNTED_STATE } imap_cmd_refcounted_state_t; typedef union { imap_cmd_t gen; struct { IMAP_CMD imap_cmd_refcounted_state_t *state; }; } imap_cmd_refcounted_t; #define CAP(cap) (ctx->caps & (1 << (cap))) enum CAPABILITY { NOLOGIN = 0, #ifdef HAVE_LIBSASL SASLIR, #endif #ifdef HAVE_LIBSSL STARTTLS, #endif UIDPLUS, LITERALPLUS, MOVE, NAMESPACE, COMPRESS_DEFLATE }; static const char *cap_list[] = { "LOGINDISABLED", #ifdef HAVE_LIBSASL "SASL-IR", #endif #ifdef HAVE_LIBSSL "STARTTLS", #endif "UIDPLUS", "LITERAL+", "MOVE", "NAMESPACE", "COMPRESS=DEFLATE" }; #define RESP_OK 0 #define RESP_NO 1 #define RESP_CANCEL 2 static INLINE void imap_ref( imap_store_t *ctx ) { ++ctx->ref_count; } static int imap_deref( imap_store_t *ctx ); static void imap_invoke_bad_callback( imap_store_t *ctx ); /* Keep the mailbox driver flag definitions in sync: */ /* grep for MAILBOX_DRIVER_FLAG */ /* The order is according to alphabetical maildir flag sort */ static const char *Flags[] = { "\\Draft", /* 'D' */ "\\Flagged", /* 'F' */ "$Forwarded", /* 'P' */ "\\Answered", /* 'R' */ "\\Seen", /* 'S' */ "\\Deleted", /* 'T' */ }; static imap_cmd_t * new_imap_cmd( uint size ) { imap_cmd_t *cmd = nfmalloc( size ); memset( &cmd->param, 0, sizeof(cmd->param) ); return cmd; } #define INIT_IMAP_CMD(type, cmdp, cb, aux) \ cmdp = (type *)new_imap_cmd( sizeof(*cmdp) ); \ cmdp->callback = cb; \ cmdp->callback_aux = aux; #define INIT_IMAP_CMD_X(type, cmdp, cb, aux) \ cmdp = (type *)new_imap_cmd( sizeof(*cmdp) ); \ cmdp->callback = cb; \ cmdp->callback_aux = aux; static void done_imap_cmd( imap_store_t *ctx, imap_cmd_t *cmd, int response ) { if (cmd->param.wait_check) ctx->num_wait_check--; cmd->param.done( ctx, cmd, response ); if (cmd->param.data) { free( cmd->param.data ); ctx->buffer_mem -= cmd->param.data_len; } free( cmd->cmd ); free( cmd ); } static void send_imap_cmd( imap_store_t *ctx, imap_cmd_t *cmd ) { int litplus, iovcnt = 3; uint tbufl, lbufl; conn_iovec_t iov[5]; char tagbuf[16]; char lenbuf[16]; cmd->tag = ++ctx->nexttag; tbufl = nfsnprintf( tagbuf, sizeof(tagbuf), "%d ", cmd->tag ); if (!cmd->param.data) { memcpy( lenbuf, "\r\n", 3 ); lbufl = 2; litplus = 0; } else if ((cmd->param.to_trash && ctx->trashnc == TrashUnknown) || !CAP(LITERALPLUS) || cmd->param.data_len >= 100*1024) { lbufl = nfsnprintf( lenbuf, sizeof(lenbuf), "{%u}\r\n", cmd->param.data_len ); litplus = 0; } else { lbufl = nfsnprintf( lenbuf, sizeof(lenbuf), "{%u+}\r\n", cmd->param.data_len ); litplus = 1; } if (DFlags & DEBUG_NET) { if (ctx->num_in_progress) printf( "(%d in progress) ", ctx->num_in_progress ); if (starts_with( cmd->cmd, -1, "LOGIN", 5 )) printf( "%s>>> %sLOGIN \r\n", ctx->label, tagbuf ); else if (starts_with( cmd->cmd, -1, "AUTHENTICATE PLAIN", 18 )) printf( "%s>>> %sAUTHENTICATE PLAIN \r\n", ctx->label, tagbuf ); else printf( "%s>>> %s%s%s", ctx->label, tagbuf, cmd->cmd, lenbuf ); fflush( stdout ); } iov[0].buf = tagbuf; iov[0].len = tbufl; iov[0].takeOwn = KeepOwn; iov[1].buf = cmd->cmd; iov[1].len = strlen( cmd->cmd ); iov[1].takeOwn = KeepOwn; iov[2].buf = lenbuf; iov[2].len = lbufl; iov[2].takeOwn = KeepOwn; if (litplus) { if (DFlags & DEBUG_NET_ALL) { printf( "%s>>>>>>>>>\n", ctx->label ); fwrite( cmd->param.data, cmd->param.data_len, 1, stdout ); printf( "%s>>>>>>>>>\n", ctx->label ); fflush( stdout ); } iov[3].buf = cmd->param.data; iov[3].len = cmd->param.data_len; iov[3].takeOwn = GiveOwn; cmd->param.data = NULL; ctx->buffer_mem -= cmd->param.data_len; iov[4].buf = "\r\n"; iov[4].len = 2; iov[4].takeOwn = KeepOwn; iovcnt = 5; } socket_write( &ctx->conn, iov, iovcnt ); if (cmd->param.to_trash && ctx->trashnc == TrashUnknown) ctx->trashnc = TrashChecking; cmd->next = NULL; *ctx->in_progress_append = cmd; ctx->in_progress_append = &cmd->next; ctx->num_in_progress++; socket_expect_activity( &ctx->conn, 1 ); } static int cmd_sendable( imap_store_t *ctx, imap_cmd_t *cmd ) { if (ctx->conn.write_buf) { /* Don't build up a long queue in the socket, so we can * control when the commands are actually sent. * This allows reliable cancelation of pending commands, * injecting commands in front of other pending commands, * and keeping num_in_progress accurate. */ return 0; } if (ctx->in_progress) { /* If the last command in flight ... */ imap_cmd_t *cmdp = (imap_cmd_t *)((char *)ctx->in_progress_append - offsetof(imap_cmd_t, next)); if (cmdp->param.cont || cmdp->param.data) { /* ... is expected to trigger a continuation request, we need to * wait for that round-trip before sending the next command. */ return 0; } } if (cmd->param.to_trash && ctx->trashnc == TrashChecking) { /* Don't build a queue of MOVE/COPY/APPEND commands that may all fail. */ return 0; } if (ctx->num_in_progress >= ctx->conf->server->max_in_progress) { /* Too many commands in flight. */ return 0; } return 1; } static void flush_imap_cmds( imap_store_t *ctx ) { imap_cmd_t *cmd; if ((cmd = ctx->pending) && cmd_sendable( ctx, cmd )) { if (!(ctx->pending = cmd->next)) ctx->pending_append = &ctx->pending; send_imap_cmd( ctx, cmd ); } } static void finalize_checked_imap_cmds( imap_store_t *ctx, int resp ) { imap_cmd_t *cmd; while ((cmd = ctx->wait_check)) { if (!(ctx->wait_check = cmd->next)) ctx->wait_check_append = &ctx->wait_check; done_imap_cmd( ctx, cmd, resp ); } } static void cancel_pending_imap_cmds( imap_store_t *ctx ) { imap_cmd_t *cmd; while ((cmd = ctx->pending)) { if (!(ctx->pending = cmd->next)) ctx->pending_append = &ctx->pending; done_imap_cmd( ctx, cmd, RESP_CANCEL ); } } static void cancel_sent_imap_cmds( imap_store_t *ctx ) { imap_cmd_t *cmd; socket_expect_activity( &ctx->conn, 0 ); while ((cmd = ctx->in_progress)) { ctx->in_progress = cmd->next; /* don't update num_in_progress and in_progress_append - store is dead */ done_imap_cmd( ctx, cmd, RESP_CANCEL ); } } static void submit_imap_cmd( imap_store_t *ctx, imap_cmd_t *cmd ) { assert( ctx ); assert( ctx->bad_callback ); assert( cmd ); assert( cmd->param.done ); if (cmd->param.wait_check) ctx->num_wait_check++; if ((ctx->pending && !cmd->param.high_prio) || !cmd_sendable( ctx, cmd )) { if (ctx->pending && cmd->param.high_prio) { cmd->next = ctx->pending; ctx->pending = cmd; } else { cmd->next = NULL; *ctx->pending_append = cmd; ctx->pending_append = &cmd->next; } } else { send_imap_cmd( ctx, cmd ); } } /* Minimal printf() replacement that supports an %\s format sequence to print backslash-escaped * string literals. Note that this does not automatically add quotes around the printed string, * so it is possible to concatenate multiple segments. */ static char * imap_vprintf( const char *fmt, va_list ap ) { const char *s; char *d, *ed; char c; #define MAX_SEGS 16 #define add_seg(s, l) \ do { \ if (nsegs == MAX_SEGS) \ oob(); \ segs[nsegs] = s; \ segls[nsegs++] = l; \ totlen += l; \ } while (0) int nsegs = 0; uint totlen = 0; const char *segs[MAX_SEGS]; uint segls[MAX_SEGS]; char buf[1000]; d = buf; ed = d + sizeof(buf); s = fmt; for (;;) { c = *fmt; if (!c || c == '%') { uint l = fmt - s; if (l) add_seg( s, l ); if (!c) break; uint maxlen = UINT_MAX; c = *++fmt; if (c == '\\') { c = *++fmt; if (c != 's') { fputs( "Fatal: unsupported escaped format specifier. Please report a bug.\n", stderr ); abort(); } char *bd = d; s = va_arg( ap, const char * ); while ((c = *s++)) { if (d + 2 > ed) oob(); if (c == '\\' || c == '"') *d++ = '\\'; *d++ = c; } l = d - bd; if (l) add_seg( bd, l ); } else { /* \\ cannot be combined with anything else. */ if (c == '.') { c = *++fmt; if (c != '*') { fputs( "Fatal: unsupported string length specification. Please report a bug.\n", stderr ); abort(); } maxlen = va_arg( ap, uint ); c = *++fmt; } if (c == 'c') { if (d + 1 > ed) oob(); add_seg( d, 1 ); *d++ = (char)va_arg( ap , int ); } else if (c == 's') { s = va_arg( ap, const char * ); l = strnlen( s, maxlen ); if (l) add_seg( s, l ); } else if (c == 'd') { l = nfsnprintf( d, ed - d, "%d", va_arg( ap, int ) ); add_seg( d, l ); d += l; } else if (c == 'u') { l = nfsnprintf( d, ed - d, "%u", va_arg( ap, uint ) ); add_seg( d, l ); d += l; } else { fputs( "Fatal: unsupported format specifier. Please report a bug.\n", stderr ); abort(); } } s = ++fmt; } else { fmt++; } } char *out = d = nfmalloc( totlen + 1 ); for (int i = 0; i < nsegs; i++) { memcpy( d, segs[i], segls[i] ); d += segls[i]; } *d = 0; return out; } static void imap_exec( imap_store_t *ctx, imap_cmd_t *cmdp, void (*done)( imap_store_t *ctx, imap_cmd_t *cmd, int response ), const char *fmt, ... ) { va_list ap; if (!cmdp) cmdp = new_imap_cmd( sizeof(*cmdp) ); cmdp->param.done = done; va_start( ap, fmt ); cmdp->cmd = imap_vprintf( fmt, ap ); va_end( ap ); submit_imap_cmd( ctx, cmdp ); } static void transform_box_response( int *response ) { switch (*response) { case RESP_CANCEL: *response = DRV_CANCELED; break; case RESP_NO: *response = DRV_BOX_BAD; break; default: *response = DRV_OK; break; } } static void imap_done_simple_box( imap_store_t *ctx ATTR_UNUSED, imap_cmd_t *cmd, int response ) { imap_cmd_simple_t *cmdp = (imap_cmd_simple_t *)cmd; transform_box_response( &response ); cmdp->callback( response, cmdp->callback_aux ); } static void transform_msg_response( int *response ) { switch (*response) { case RESP_CANCEL: *response = DRV_CANCELED; break; case RESP_NO: *response = DRV_MSG_BAD; break; default: *response = DRV_OK; break; } } static void imap_done_simple_msg( imap_store_t *ctx ATTR_UNUSED, imap_cmd_t *cmd, int response ) { imap_cmd_simple_t *cmdp = (imap_cmd_simple_t *)cmd; transform_msg_response( &response ); cmdp->callback( response, cmdp->callback_aux ); } static imap_cmd_refcounted_state_t * imap_refcounted_new_state( uint sz ) { imap_cmd_refcounted_state_t *sts = nfmalloc( sz ); sts->ref_count = 1; /* so forced sync does not cause an early exit */ sts->ret_val = DRV_OK; return sts; } #define INIT_REFCOUNTED_STATE(type, sts, cb, aux) \ type *sts = (type *)imap_refcounted_new_state( sizeof(type) ); \ sts->callback = cb; \ sts->callback_aux = aux; static imap_cmd_t * imap_refcounted_new_cmd( imap_cmd_refcounted_state_t *sts ) { imap_cmd_refcounted_t *cmd = (imap_cmd_refcounted_t *)new_imap_cmd( sizeof(*cmd) ); cmd->state = sts; sts->ref_count++; return &cmd->gen; } #define DONE_REFCOUNTED_STATE(sts) \ if (!--sts->ref_count) { \ sts->callback( sts->ret_val, sts->callback_aux ); \ free( sts ); \ } #define DONE_REFCOUNTED_STATE_ARGS(sts, finalize, ...) \ if (!--sts->ref_count) { \ finalize \ sts->callback( sts->ret_val, __VA_ARGS__, sts->callback_aux ); \ free( sts ); \ } static void transform_refcounted_box_response( imap_cmd_refcounted_state_t *sts, int response ) { switch (response) { case RESP_CANCEL: sts->ret_val = DRV_CANCELED; break; case RESP_NO: if (sts->ret_val == DRV_OK) /* Don't override cancelation. */ sts->ret_val = DRV_BOX_BAD; break; } } static void transform_refcounted_msg_response( imap_cmd_refcounted_state_t *sts, int response ) { switch (response) { case RESP_CANCEL: sts->ret_val = DRV_CANCELED; break; case RESP_NO: if (sts->ret_val == DRV_OK) /* Don't override cancelation. */ sts->ret_val = DRV_MSG_BAD; break; } } static const char * imap_strchr( const char *s, char tc ) { for (;; s++) { char c = *s; if (c == '\\') c = *++s; if (!c) return NULL; if (c == tc) return s; } } static char * next_arg( char **ps ) { char *ret, *s, *d; char c; assert( ps ); s = *ps; if (!s) return NULL; while (isspace( (uchar)*s )) s++; if (!*s) { *ps = NULL; return NULL; } if (*s == '"') { s++; ret = d = s; while ((c = *s++) != '"') { if (c == '\\') c = *s++; if (!c) { *ps = NULL; return NULL; } *d++ = c; } *d = 0; } else { ret = s; while ((c = *s)) { if (isspace( (uchar)c )) { *s++ = 0; break; } s++; } } if (!*s) s = NULL; *ps = s; return ret; } static int is_opt_atom( list_t *list ) { return list && list->val && list->val != LIST; } static int is_atom( list_t *list ) { return list && list->val && list->val != NIL && list->val != LIST; } static int is_list( list_t *list ) { return list && list->val == LIST; } static void free_list( list_t *list ) { list_t *tmp; for (; list; list = tmp) { tmp = list->next; if (is_list( list )) free_list( list->child ); else if (is_atom( list )) free( list->val ); free( list ); } } enum { LIST_OK, LIST_PARTIAL, LIST_BAD }; static int parse_imap_list( imap_store_t *ctx, char **sp, parse_list_state_t *sts ) { list_t *cur, **curp; char *s = *sp, *d, *p; int n, bytes; char c; assert( sts ); assert( sts->level > 0 ); curp = sts->stack[--sts->level]; bytes = sts->need_bytes; if (bytes >= 0) { sts->need_bytes = -1; if (!bytes) goto getline; cur = (list_t *)((char *)curp - offsetof(list_t, next)); s = cur->val + cur->len - bytes; goto getbytes; } if (!s) return LIST_BAD; for (;;) { while (isspace( (uchar)*s )) s++; if (sts->level && *s == ')') { s++; curp = sts->stack[--sts->level]; goto next; } *curp = cur = nfmalloc( sizeof(*cur) ); cur->val = NULL; /* for clean bail */ curp = &cur->next; *curp = NULL; /* ditto */ if (*s == '(') { /* sublist */ if (sts->level == MAX_LIST_DEPTH) goto bail; s++; cur->val = LIST; sts->stack[sts->level++] = curp; curp = &cur->child; *curp = NULL; /* for clean bail */ goto next2; } else if (ctx && *s == '{') { /* literal */ bytes = (int)(cur->len = strtoul( s + 1, &s, 10 )); if (*s != '}' || *++s) goto bail; if ((uint)bytes >= INT_MAX) { error( "IMAP error: excessively large literal from %s " "- THIS MIGHT BE AN ATTEMPT TO HACK YOU!\n", ctx->conn.name ); goto bail; } s = cur->val = nfmalloc( cur->len + 1 ); s[cur->len] = 0; getbytes: n = socket_read( &ctx->conn, s, (uint)bytes ); if (n < 0) { badeof: error( "IMAP error: unexpected EOF from %s\n", ctx->conn.name ); goto bail; } bytes -= n; if (bytes > 0) goto postpone; if (DFlags & DEBUG_NET_ALL) { printf( "%s=========\n", ctx->label ); fwrite( cur->val, cur->len, 1, stdout ); printf( "%s=========\n", ctx->label ); fflush( stdout ); } getline: if (!(s = socket_read_line( &ctx->conn ))) goto postpone; if (s == (void *)~0) goto badeof; if (DFlags & DEBUG_NET) { printf( "%s%s\n", ctx->label, s ); fflush( stdout ); } } else if (*s == '"') { /* quoted string */ s++; p = d = s; while ((c = *s++) != '"') { if (c == '\\') c = *s++; if (!c) goto bail; *d++ = c; } cur->len = (uint)(d - p); cur->val = nfstrndup( p, cur->len ); } else { /* atom */ p = s; for (; *s && !isspace( (uchar)*s ); s++) if (sts->level && *s == ')') break; cur->len = (uint)(s - p); if (equals( p, (int)cur->len, "NIL", 3 )) cur->val = NIL; else cur->val = nfstrndup( p, cur->len ); } next: if (!sts->level) break; next2: if (!*s) goto bail; } *sp = s; return LIST_OK; postpone: if (sts->level < MAX_LIST_DEPTH) { sts->stack[sts->level++] = curp; sts->need_bytes = bytes; return LIST_PARTIAL; } bail: free_list( sts->head ); sts->level = 0; return LIST_BAD; } static void parse_list_init( parse_list_state_t *sts ) { sts->need_bytes = -1; sts->level = 1; sts->head = NULL; sts->stack[0] = &sts->head; } static int parse_list_continue( imap_store_t *ctx, char *s ) { list_t *list; int resp; if ((resp = parse_imap_list( ctx, &s, &ctx->parse_list_sts )) != LIST_PARTIAL) { list = (resp == LIST_BAD) ? NULL : ctx->parse_list_sts.head; ctx->parse_list_sts.head = NULL; resp = ctx->parse_list_sts.callback( ctx, list, s ); free_list( list ); } return resp; } static int parse_list( imap_store_t *ctx, char *s, int (*cb)( imap_store_t *ctx, list_t *list, char *s ) ) { parse_list_init( &ctx->parse_list_sts ); ctx->parse_list_sts.callback = cb; return parse_list_continue( ctx, s ); } static int parse_namespace_rsp_p2( imap_store_t *, list_t *, char * ); static int parse_namespace_rsp_p3( imap_store_t *, list_t *, char * ); static int parse_namespace_rsp( imap_store_t *ctx, list_t *list, char *s ) { // We use only the 1st personal namespace. Making this configurable // would not add value over just specifying Path. if (!list) { bad: error( "IMAP error: malformed NAMESPACE response\n" ); return LIST_BAD; } if (list->val != NIL) { if (list->val != LIST) goto bad; list_t *nsp_1st = list->child; if (nsp_1st->val != LIST) goto bad; list_t *nsp_1st_ns = nsp_1st->child; if (!is_atom( nsp_1st_ns )) goto bad; ctx->ns_prefix = nsp_1st_ns->val; nsp_1st_ns->val = NULL; list_t *nsp_1st_dl = nsp_1st_ns->next; if (!is_opt_atom( nsp_1st_dl )) goto bad; if (is_atom( nsp_1st_dl )) ctx->ns_delimiter = nsp_1st_dl->val[0]; // Namespace response extensions may follow here; we don't care. } return parse_list( ctx, s, parse_namespace_rsp_p2 ); } static int parse_namespace_rsp_p2( imap_store_t *ctx, list_t *list ATTR_UNUSED, char *s ) { return parse_list( ctx, s, parse_namespace_rsp_p3 ); } static int parse_namespace_rsp_p3( imap_store_t *ctx ATTR_UNUSED, list_t *list ATTR_UNUSED, char *s ATTR_UNUSED ) { return LIST_OK; } static time_t parse_date( const char *str ) { char *end; time_t date; int hours, mins; struct tm datetime; memset( &datetime, 0, sizeof(datetime) ); if (!(end = strptime( str, "%e-%b-%Y %H:%M:%S ", &datetime ))) return -1; if ((date = timegm( &datetime )) == -1) return -1; if (sscanf( end, "%3d%2d", &hours, &mins ) != 2) return -1; return date - (hours * 60 + mins) * 60; } static int parse_fetched_flags( list_t *list, uchar *flags, uchar *status ) { for (; list; list = list->next) { if (!is_atom( list )) { error( "IMAP error: unable to parse FLAGS list\n" ); return 0; } if (list->val[0] != '\\' && list->val[0] != '$') continue; if (!strcmp( "\\Recent", list->val )) { *status |= M_RECENT; goto flagok; } for (uint i = 0; i < as(Flags); i++) { if (!strcmp( Flags[i], list->val )) { *flags |= 1 << i; goto flagok; } } if (list->val[0] == '$') goto flagok; // Ignore unknown user-defined flags (keywords) if (list->val[1] == 'X' && list->val[2] == '-') goto flagok; // Ignore system flag extensions warn( "IMAP warning: unknown system flag %s\n", list->val ); flagok: ; } return 1; } static void parse_fetched_header( char *val, uint uid, char **tuid, char **msgid, uint *msgid_len ) { char *end; int off, in_msgid = 0; for (; (end = strchr( val, '\n' )); val = end + 1) { int len = (int)(end - val); if (len && end[-1] == '\r') len--; if (!len) break; if (starts_with_upper( val, len, "X-TUID: ", 8 )) { if (len < 8 + TUIDL) { warn( "IMAP warning: malformed X-TUID header (UID %u)\n", uid ); continue; } *tuid = val + 8; in_msgid = 0; continue; } if (starts_with_upper( val, len, "MESSAGE-ID:", 11 )) { off = 11; } else if (in_msgid) { if (!isspace( val[0] )) { in_msgid = 0; continue; } off = 1; } else { continue; } while (off < len && isspace( val[off] )) off++; if (off == len) { in_msgid = 1; continue; } *msgid = val + off; *msgid_len = (uint)(len - off); in_msgid = 0; } } static int parse_fetch_rsp( imap_store_t *ctx, list_t *list, char *s ATTR_UNUSED ) { list_t *body = NULL, *tmp; char *tuid = NULL, *msgid = NULL, *ep; imap_message_t *cur; msg_data_t *msgdata; imap_cmd_t *cmdp; uchar mask = 0, status = 0; uint uid = 0, size = 0, msgid_len = 0; time_t date = 0; if (!is_list( list )) { error( "IMAP error: bogus FETCH response\n" ); return LIST_BAD; } for (tmp = list->child; tmp; tmp = tmp->next) { if (!is_atom( tmp )) { error( "IMAP error: bogus item name in FETCH response\n" ); return LIST_BAD; } const char *name = tmp->val; tmp = tmp->next; if (!strcmp( "UID", name )) { if (!is_atom( tmp ) || (uid = strtoul( tmp->val, &ep, 10 ), *ep)) { error( "IMAP error: unable to parse UID\n" ); return LIST_BAD; } } else if (!strcmp( "FLAGS", name )) { if (!is_list( tmp )) { error( "IMAP error: unable to parse FLAGS\n" ); return LIST_BAD; } if (!parse_fetched_flags( tmp->child, &mask, &status )) return LIST_BAD; status |= M_FLAGS; } else if (!strcmp( "INTERNALDATE", name )) { if (!is_atom( tmp )) { error( "IMAP error: unable to parse INTERNALDATE\n" ); return LIST_BAD; } if ((date = parse_date( tmp->val )) == -1) { error( "IMAP error: unable to parse INTERNALDATE format\n" ); return LIST_BAD; } status |= M_DATE; } else if (!strcmp( "RFC822.SIZE", name )) { if (!is_atom( tmp ) || (size = strtoul( tmp->val, &ep, 10 ), *ep)) { error( "IMAP error: unable to parse RFC822.SIZE\n" ); return LIST_BAD; } status |= M_SIZE; } else if (!strcmp( "BODY[]", name ) || !strcmp( "BODY[HEADER]", name )) { if (!is_atom( tmp )) { error( "IMAP error: unable to parse BODY[]\n" ); return LIST_BAD; } body = tmp; status |= M_BODY; } else if (!strcmp( "BODY[HEADER.FIELDS", name )) { if (!is_list( tmp )) { bfail: error( "IMAP error: unable to parse BODY[HEADER.FIELDS ...]\n" ); return LIST_BAD; } tmp = tmp->next; if (!is_atom( tmp ) || strcmp( tmp->val, "]" )) goto bfail; tmp = tmp->next; if (!is_atom( tmp )) goto bfail; parse_fetched_header( tmp->val, uid, &tuid, &msgid, &msgid_len ); status |= M_HEADER; } } if (!uid) { // Ignore async flag updates for now. status &= ~(M_FLAGS | M_RECENT); } else if (status & M_BODY) { for (cmdp = ctx->in_progress; cmdp; cmdp = cmdp->next) if (cmdp->param.uid == uid) goto gotuid; error( "IMAP error: unexpected FETCH response with BODY (UID %u)\n", uid ); return LIST_BAD; gotuid: msgdata = ((imap_cmd_fetch_msg_t *)cmdp)->msg_data; msgdata->data = body->val; body->val = NULL; // Don't free together with list. msgdata->len = body->len; msgdata->date = date; if (status & M_FLAGS) msgdata->flags = mask; status &= ~(M_FLAGS | M_RECENT | M_BODY | M_DATE); } else if (ctx->fetch_sts == FetchUidNext) { // Workaround for server not sending UIDNEXT and/or APPENDUID. ctx->uidnext = uid + 1; } else if (ctx->fetch_sts == FetchMsgs) { cur = nfcalloc( sizeof(*cur) ); *ctx->msgapp = cur; ctx->msgapp = &cur->next; cur->uid = uid; cur->flags = mask; cur->status = status; cur->size = size; if (msgid) cur->msgid = nfstrndup( msgid, msgid_len ); if (tuid) memcpy( cur->tuid, tuid, TUIDL ); status &= ~(M_FLAGS | M_RECENT | M_SIZE | M_HEADER); } else { // These may come in as a result of STORE FLAGS despite .SILENT. status &= ~(M_FLAGS | M_RECENT); } if (status) { error( "IMAP error: received extraneous data in FETCH response\n" ); return LIST_BAD; } return LIST_OK; } static void parse_capability( imap_store_t *ctx, char *cmd ) { char *arg; uint i; free_string_list( ctx->auth_mechs ); ctx->auth_mechs = NULL; ctx->caps = 0x80000000; while ((arg = next_arg( &cmd ))) { if (starts_with( arg, -1, "AUTH=", 5 )) { add_string_list( &ctx->auth_mechs, arg + 5 ); } else { for (i = 0; i < as(cap_list); i++) if (!strcmp( cap_list[i], arg )) ctx->caps |= 1 << i; } } ctx->caps &= ~ctx->conf->server->cap_mask; if (!CAP(NOLOGIN)) add_string_list( &ctx->auth_mechs, "LOGIN" ); } static int parse_response_code( imap_store_t *ctx, imap_cmd_t *cmd, char *s ) { char *arg, *earg, *p; if (!s || *s != '[') return RESP_OK; /* no response code */ s++; if (!(arg = next_arg( &s ))) { error( "IMAP error: malformed response code\n" ); return RESP_CANCEL; } if (!strcmp( "UIDVALIDITY", arg )) { if (!(arg = next_arg( &s )) || (ctx->uidvalidity = strtoul( arg, &earg, 10 ), *earg != ']')) { error( "IMAP error: malformed UIDVALIDITY status\n" ); return RESP_CANCEL; } } else if (!strcmp( "UIDNEXT", arg )) { if (!(arg = next_arg( &s )) || (ctx->uidnext = strtoul( arg, &earg, 10 ), *earg != ']')) { error( "IMAP error: malformed UIDNEXT status\n" ); return RESP_CANCEL; } } else if (!strcmp( "CAPABILITY", arg )) { if (!s || !(p = strchr( s, ']' ))) { error( "IMAP error: malformed CAPABILITY status\n" ); return RESP_CANCEL; } *p = 0; parse_capability( ctx, s ); } else if (!strcmp( "ALERT]", arg )) { /* RFC2060 says that these messages MUST be displayed * to the user */ if (!s) { error( "IMAP error: malformed ALERT status\n" ); return RESP_CANCEL; } for (; isspace( (uchar)*s ); s++); error( "*** IMAP ALERT *** %s\n", s ); } else if (!strcmp( "APPENDUID", arg )) { // The checks ensure that: // - cmd => this is the final tagged response of a command, at which // point cmd was already removed from ctx->in_progress, so param.uid // is available for reuse. // - !param.uid => the command isn't actually a FETCH. This doesn't // really matter, as the field is safe to overwrite given the // previous condition; it just has no effect for non-APPENDs. if (!cmd || cmd->param.uid) { error( "IMAP error: unexpected APPENDUID status\n" ); return RESP_CANCEL; } if (!(arg = next_arg( &s )) || (ctx->uidvalidity = strtoul( arg, &earg, 10 ), *earg) || !(arg = next_arg( &s )) || (cmd->param.uid = strtoul( arg, &earg, 10 ), *earg != ']')) { error( "IMAP error: malformed APPENDUID status\n" ); return RESP_CANCEL; } } else if (!strcmp( "PERMANENTFLAGS", arg )) { parse_list_init( &ctx->parse_list_sts ); if (parse_imap_list( NULL, &s, &ctx->parse_list_sts ) != LIST_OK || *s != ']') { error( "IMAP error: malformed PERMANENTFLAGS status\n" ); return RESP_CANCEL; } int ret = RESP_OK; for (list_t *tmp = ctx->parse_list_sts.head->child; tmp; tmp = tmp->next) { if (!is_atom( tmp )) { error( "IMAP error: malformed PERMANENTFLAGS status item\n" ); ret = RESP_CANCEL; break; } if (!strcmp( tmp->val, "\\*" ) || !strcmp( tmp->val, "$Forwarded" )) { ctx->has_forwarded = 1; break; } } free_list( ctx->parse_list_sts.head ); ctx->parse_list_sts.head = NULL; return ret; } return RESP_OK; } static int parse_list_rsp_p1( imap_store_t *, list_t *, char * ); static int parse_list_rsp_p2( imap_store_t *, list_t *, char * ); static int parse_list_rsp( imap_store_t *ctx, list_t *list, char *cmd ) { list_t *lp; if (!is_list( list )) { error( "IMAP error: malformed LIST response\n" ); return LIST_BAD; } for (lp = list->child; lp; lp = lp->next) if (is_atom( lp ) && !strcasecmp( lp->val, "\\NoSelect" )) return LIST_OK; return parse_list( ctx, cmd, parse_list_rsp_p1 ); } static int parse_list_rsp_p1( imap_store_t *ctx, list_t *list, char *cmd ATTR_UNUSED ) { if (!is_opt_atom( list )) { error( "IMAP error: malformed LIST response\n" ); return LIST_BAD; } if (!ctx->delimiter[0] && is_atom( list )) ctx->delimiter[0] = list->val[0]; return parse_list( ctx, cmd, parse_list_rsp_p2 ); } // Use this to check whether a full path refers to the actual IMAP INBOX. static int is_inbox( imap_store_t *ctx, const char *arg, int argl ) { if (!starts_with_upper( arg, argl, "INBOX", 5 )) return 0; if (arg[5] && arg[5] != ctx->delimiter[0]) return 0; return 1; } // Use this to check whether a path fragment collides with the canonical INBOX. static int is_INBOX( imap_store_t *ctx, const char *arg, int argl ) { if (!starts_with( arg, argl, "INBOX", 5 )) return 0; if (arg[5] && arg[5] != ctx->delimiter[0]) return 0; return 1; } static void normalize_INBOX( imap_store_t *ctx, char *arg, int argl ) { if (is_inbox( ctx, arg, argl )) memcpy( arg, "INBOX", 5 ); } static int parse_list_rsp_p2( imap_store_t *ctx, list_t *list, char *cmd ATTR_UNUSED ) { string_list_t *narg; char *arg, c; int argl; uint l; if (!is_atom( list )) { error( "IMAP error: malformed LIST response\n" ); return LIST_BAD; } arg = list->val; argl = (int)list->len; if (argl > 1000) { warn( "IMAP warning: ignoring unreasonably long mailbox name '%.100s[...]'\n", arg ); return LIST_OK; } // The server might be weird and have a non-uppercase INBOX. It // may legitimately do so, but we need the canonical spelling. normalize_INBOX( ctx, arg, argl ); if ((l = strlen( ctx->prefix ))) { if (!starts_with( arg, argl, ctx->prefix, l )) { if (!is_INBOX( ctx, arg, argl )) return LIST_OK; // INBOX and its subfolders bypass the namespace. } else { arg += l; argl -= l; // A folder named "INBOX" would be indistinguishable from the // actual INBOX after prefix stripping, so drop it. This applies // only to the fully uppercased spelling, as our canonical box // names are case-sensitive (unlike IMAP's INBOX). if (is_INBOX( ctx, arg, argl )) { if (!arg[5]) // No need to complain about subfolders as well. warn( "IMAP warning: ignoring INBOX in %s\n", ctx->prefix ); return LIST_OK; } } } if (argl >= 5 && !memcmp( arg + argl - 5, ".lock", 5 )) /* workaround broken servers */ return LIST_OK; if (map_name( arg, (char **)&narg, offsetof(string_list_t, string), ctx->delimiter, "/") < 0) { warn( "IMAP warning: ignoring mailbox %s (reserved character '/' in name)\n", arg ); return LIST_OK; } // Validate the normalized name. Technically speaking, we could tolerate // '//' and '/./', and '/../' being forbidden is a limitation of the Maildir // driver, but there isn't really a legitimate reason for these being present. for (const char *p = narg->string, *sp = p;;) { if (!(c = *p) || c == '/') { uint pcl = (uint)(p - sp); if (!pcl) { error( "IMAP warning: ignoring mailbox '%s' due to empty name component\n", narg->string ); free( narg ); return LIST_OK; } if (pcl == 1 && sp[0] == '.') { error( "IMAP warning: ignoring mailbox '%s' due to '.' component\n", narg->string ); free( narg ); return LIST_OK; } if (pcl == 2 && sp[0] == '.' && sp[1] == '.') { error( "IMAP error: LIST'd mailbox name '%s' contains '..' component - THIS MIGHT BE AN ATTEMPT TO HACK YOU!\n", narg->string ); free( narg ); return LIST_BAD; } if (!c) break; sp = ++p; } else { ++p; } } narg->next = ctx->boxes; ctx->boxes = narg; return LIST_OK; } static int prepare_name( char **buf, const imap_store_t *ctx, const char *prefix, const char *name ) { uint pl = strlen( prefix ); switch (map_name( name, buf, pl, "/", ctx->delimiter )) { case -1: error( "IMAP error: mailbox name %s contains server's hierarchy delimiter\n", name ); return -1; case -2: error( "IMAP error: server's hierarchy delimiter not known\n" ); return -1; default: memcpy( *buf, prefix, pl ); return 0; } } static int prepare_box( char **buf, const imap_store_t *ctx ) { const char *name = ctx->name; const char *pfx = ctx->prefix; if (starts_with_upper( name, -1, "INBOX", 5 ) && (!name[5] || name[5] == '/')) { if (!memcmp( name, "INBOX", 5 )) { pfx = ""; } else if (!*pfx) { error( "IMAP error: cannot use unqualified '%s'. Did you mean INBOX?", name ); return -1; } } return prepare_name( buf, ctx, pfx, name ); } static int prepare_trash( char **buf, const imap_store_t *ctx ) { return prepare_name( buf, ctx, ctx->prefix, ctx->conf->trash ); } typedef union { imap_cmd_t gen; struct { IMAP_CMD imap_cmd_t *orig_cmd; }; } imap_cmd_trycreate_t; static void imap_open_store_greeted( imap_store_t * ); static void get_cmd_result_p2( imap_store_t *, imap_cmd_t *, int ); static void imap_socket_read( void *aux ) { imap_store_t *ctx = (imap_store_t *)aux; imap_cmd_t *cmdp, **pcmdp; char *cmd, *arg, *arg1, *p; int resp, resp2, tag; conn_iovec_t iov[2]; for (;;) { if (ctx->parse_list_sts.level) { resp = parse_list_continue( ctx, NULL ); listret: if (resp == LIST_PARTIAL) return; if (resp == LIST_BAD) break; continue; } if (!(cmd = socket_read_line( &ctx->conn ))) return; if (cmd == (void *)~0) { if (!ctx->expectEOF) error( "IMAP error: unexpected EOF from %s\n", ctx->conn.name ); /* A clean shutdown sequence ends with bad_callback as well (see imap_cleanup()). */ break; } if (DFlags & DEBUG_NET) { printf( "%s%s\n", ctx->label, cmd ); fflush( stdout ); } arg = next_arg( &cmd ); if (!arg) { error( "IMAP error: empty response\n" ); break; } if (*arg == '*') { arg = next_arg( &cmd ); if (!arg) { error( "IMAP error: malformed untagged response\n" ); break; } if (ctx->greeting == GreetingPending && !strcmp( "PREAUTH", arg )) { parse_response_code( ctx, NULL, cmd ); ctx->greeting = GreetingPreauth; dogreet: imap_ref( ctx ); imap_open_store_greeted( ctx ); if (imap_deref( ctx )) return; } else if (!strcmp( "OK", arg )) { parse_response_code( ctx, NULL, cmd ); if (ctx->greeting == GreetingPending) { ctx->greeting = GreetingOk; goto dogreet; } } else if (!strcmp( "BYE", arg )) { if (!ctx->expectBYE) { ctx->greeting = GreetingBad; error( "IMAP error: unexpected BYE response: %s\n", cmd ); /* We just wait for the server to close the connection now. */ ctx->expectEOF = 1; } else { /* We still need to wait for the LOGOUT's tagged OK. */ } } else if (ctx->greeting == GreetingPending) { error( "IMAP error: bogus greeting response %s\n", arg ); break; } else if (!strcmp( "NO", arg )) { warn( "Warning from IMAP server: %s\n", cmd ); } else if (!strcmp( "BAD", arg )) { error( "Error from IMAP server: %s\n", cmd ); } else if (!strcmp( "CAPABILITY", arg )) { parse_capability( ctx, cmd ); } else if (!strcmp( "LIST", arg ) || !strcmp( "LSUB", arg )) { resp = parse_list( ctx, cmd, parse_list_rsp ); goto listret; } else if (!strcmp( "NAMESPACE", arg )) { resp = parse_list( ctx, cmd, parse_namespace_rsp ); goto listret; } else if ((arg1 = next_arg( &cmd ))) { if (!strcmp( "EXISTS", arg1 )) ctx->total_msgs = atoi( arg ); else if (!strcmp( "EXPUNGE", arg1 )) ctx->total_msgs--; else if (!strcmp( "RECENT", arg1 )) ctx->recent_msgs = atoi( arg ); else if(!strcmp ( "FETCH", arg1 )) { resp = parse_list( ctx, cmd, parse_fetch_rsp ); goto listret; } } else { error( "IMAP error: unrecognized untagged response '%s'\n", arg ); break; /* this may mean anything, so prefer not to spam the log */ } continue; } else if (!ctx->in_progress) { error( "IMAP error: unexpected reply: %s %s\n", arg, cmd ? cmd : "" ); break; /* this may mean anything, so prefer not to spam the log */ } else if (*arg == '+') { socket_expect_activity( &ctx->conn, 0 ); /* There can be any number of commands in flight, but only the last * one can require a continuation, as it enforces a round-trip. */ cmdp = (imap_cmd_t *)((char *)ctx->in_progress_append - offsetof(imap_cmd_t, next)); if (cmdp->param.data) { if (cmdp->param.to_trash) ctx->trashnc = TrashKnown; /* Can't get NO [TRYCREATE] any more. */ if (DFlags & DEBUG_NET_ALL) { printf( "%s>>>>>>>>>\n", ctx->label ); fwrite( cmdp->param.data, cmdp->param.data_len, 1, stdout ); printf( "%s>>>>>>>>>\n", ctx->label ); fflush( stdout ); } iov[0].buf = cmdp->param.data; iov[0].len = cmdp->param.data_len; iov[0].takeOwn = GiveOwn; cmdp->param.data = NULL; ctx->buffer_mem -= cmdp->param.data_len; iov[1].buf = "\r\n"; iov[1].len = 2; iov[1].takeOwn = KeepOwn; socket_write( &ctx->conn, iov, 2 ); } else if (cmdp->param.cont) { if (cmdp->param.cont( ctx, cmdp, cmd )) return; } else { error( "IMAP error: unexpected command continuation request\n" ); break; } socket_expect_activity( &ctx->conn, 1 ); } else { tag = atoi( arg ); for (pcmdp = &ctx->in_progress; (cmdp = *pcmdp); pcmdp = &cmdp->next) if (cmdp->tag == tag) goto gottag; error( "IMAP error: unexpected tag %s\n", arg ); break; gottag: if (!(*pcmdp = cmdp->next)) ctx->in_progress_append = pcmdp; if (!--ctx->num_in_progress) socket_expect_activity( &ctx->conn, 0 ); arg = next_arg( &cmd ); if (!arg) { error( "IMAP error: malformed tagged response\n" ); break; } if (!strcmp( "OK", arg )) { if (cmdp->param.to_trash) ctx->trashnc = TrashKnown; /* Can't get NO [TRYCREATE] any more. */ resp = RESP_OK; } else { if (!strcmp( "NO", arg )) { if (cmdp->param.create && cmd && starts_with( cmd, -1, "[TRYCREATE]", 11 )) { /* APPEND or UID COPY */ imap_cmd_trycreate_t *cmd2 = (imap_cmd_trycreate_t *)new_imap_cmd( sizeof(*cmd2) ); cmd2->orig_cmd = cmdp; cmd2->param.high_prio = 1; p = strchr( cmdp->cmd, '"' ); imap_exec( ctx, &cmd2->gen, get_cmd_result_p2, "CREATE %.*s", imap_strchr( p + 1, '"' ) - p + 1, p ); continue; } resp = RESP_NO; if (cmdp->param.failok) goto doresp; } else /*if (!strcmp( "BAD", arg ))*/ resp = RESP_CANCEL; error( "IMAP command '%s' returned an error: %s %s\n", starts_with( cmdp->cmd, -1, "LOGIN", 5 ) ? "LOGIN " : starts_with( cmdp->cmd, -1, "AUTHENTICATE PLAIN", 18 ) ? "AUTHENTICATE PLAIN " : cmdp->cmd, arg, cmd ? cmd : "" ); } doresp: if ((resp2 = parse_response_code( ctx, cmdp, cmd )) > resp) resp = resp2; imap_ref( ctx ); if (resp == RESP_CANCEL) imap_invoke_bad_callback( ctx ); if (resp == RESP_OK && cmdp->param.wait_check) { cmdp->next = NULL; *ctx->wait_check_append = cmdp; ctx->wait_check_append = &cmdp->next; } else { done_imap_cmd( ctx, cmdp, resp ); } if (imap_deref( ctx )) return; if (ctx->canceling && !ctx->in_progress) { ctx->canceling = 0; ctx->callbacks.imap_cancel( ctx->callback_aux ); return; } } flush_imap_cmds( ctx ); } imap_invoke_bad_callback( ctx ); } static void get_cmd_result_p2( imap_store_t *ctx, imap_cmd_t *cmd, int response ) { imap_cmd_trycreate_t *cmdp = (imap_cmd_trycreate_t *)cmd; imap_cmd_t *ocmd = cmdp->orig_cmd; if (response != RESP_OK) { done_imap_cmd( ctx, ocmd, response ); } else { assert( !ocmd->param.wait_check ); ctx->uidnext = 1; if (ocmd->param.to_trash) ctx->trashnc = TrashKnown; ocmd->param.create = 0; ocmd->param.high_prio = 1; submit_imap_cmd( ctx, ocmd ); } } /******************* imap_cancel_store *******************/ static void imap_cancel_store( store_t *gctx ) { imap_store_t *ctx = (imap_store_t *)gctx; #ifdef HAVE_LIBSASL sasl_dispose( &ctx->sasl ); #endif socket_close( &ctx->conn ); finalize_checked_imap_cmds( ctx, RESP_CANCEL ); cancel_sent_imap_cmds( ctx ); cancel_pending_imap_cmds( ctx ); free( ctx->ns_prefix ); free_string_list( ctx->auth_mechs ); free_generic_messages( &ctx->msgs->gen ); free_string_list( ctx->boxes ); imap_deref( ctx ); } static int imap_deref( imap_store_t *ctx ) { if (!--ctx->ref_count) { free( ctx ); return -1; } return 0; } static void imap_set_bad_callback( store_t *gctx, void (*cb)( void *aux ), void *aux ) { imap_store_t *ctx = (imap_store_t *)gctx; ctx->bad_callback = cb; ctx->bad_callback_aux = aux; } static void imap_invoke_bad_callback( imap_store_t *ctx ) { ctx->bad_callback( ctx->bad_callback_aux ); } /******************* imap_free_store *******************/ static imap_store_t *unowned; static void imap_cancel_unowned( void *gctx ) { imap_store_t *store, **storep; for (storep = &unowned; (store = *storep); storep = &store->next) if (store == gctx) { *storep = store->next; break; } imap_cancel_store( gctx ); } static void imap_free_store( store_t *gctx ) { imap_store_t *ctx = (imap_store_t *)gctx; assert( !ctx->pending && !ctx->in_progress && !ctx->wait_check ); free_generic_messages( &ctx->msgs->gen ); ctx->msgs = NULL; imap_set_bad_callback( gctx, imap_cancel_unowned, gctx ); ctx->next = unowned; unowned = ctx; } /******************* imap_cleanup *******************/ static void imap_cleanup_p2( imap_store_t *, imap_cmd_t *, int ); static void imap_cleanup( void ) { imap_store_t *ctx, *nctx; for (ctx = unowned; ctx; ctx = nctx) { nctx = ctx->next; imap_set_bad_callback( &ctx->gen, (void (*)(void *))imap_cancel_store, ctx ); if (((imap_store_t *)ctx)->state != SST_BAD) { ((imap_store_t *)ctx)->expectBYE = 1; imap_exec( (imap_store_t *)ctx, NULL, imap_cleanup_p2, "LOGOUT" ); } else { imap_cancel_store( &ctx->gen ); } } } static void imap_cleanup_p2( imap_store_t *ctx, imap_cmd_t *cmd ATTR_UNUSED, int response ) { if (response == RESP_NO) imap_cancel_store( &ctx->gen ); else if (response == RESP_OK) ctx->expectEOF = 1; } /******************* imap_open_store *******************/ static void imap_open_store_connected( int, void * ); #ifdef HAVE_LIBSSL static void imap_open_store_tlsstarted1( int, void * ); #endif static void imap_open_store_p2( imap_store_t *, imap_cmd_t *, int ); static void imap_open_store_authenticate( imap_store_t * ); #ifdef HAVE_LIBSSL static void imap_open_store_authenticate_p2( imap_store_t *, imap_cmd_t *, int ); static void imap_open_store_tlsstarted2( int, void * ); static void imap_open_store_authenticate_p3( imap_store_t *, imap_cmd_t *, int ); #endif static void imap_open_store_authenticate2( imap_store_t * ); static void imap_open_store_authenticate2_p2( imap_store_t *, imap_cmd_t *, int ); static void imap_open_store_compress( imap_store_t * ); #ifdef HAVE_LIBZ static void imap_open_store_compress_p2( imap_store_t *, imap_cmd_t *, int ); #endif static void imap_open_store_namespace( imap_store_t * ); static void imap_open_store_namespace_p2( imap_store_t *, imap_cmd_t *, int ); static void imap_open_store_namespace2( imap_store_t * ); static void imap_open_store_finalize( imap_store_t * ); #ifdef HAVE_LIBSSL static void imap_open_store_ssl_bail( imap_store_t * ); #endif static void imap_open_store_bail( imap_store_t *, int ); static store_t * imap_alloc_store( store_conf_t *conf, const char *label ) { imap_store_conf_t *cfg = (imap_store_conf_t *)conf; imap_server_conf_t *srvc = cfg->server; imap_store_t *ctx, **ctxp; /* First try to recycle a whole store. */ for (ctxp = &unowned; (ctx = *ctxp); ctxp = &ctx->next) if (ctx->state == SST_GOOD && ctx->conf == cfg) { *ctxp = ctx->next; goto gotstore; } /* Then try to recycle a server connection. */ for (ctxp = &unowned; (ctx = *ctxp); ctxp = &ctx->next) if (ctx->state != SST_BAD && ctx->conf->server == srvc) { *ctxp = ctx->next; free_string_list( ctx->boxes ); ctx->boxes = NULL; ctx->listed = 0; /* One could ping the server here, but given that the idle timeout * is at least 30 minutes, this sounds pretty pointless. */ ctx->state = SST_HALF; goto gotsrv; } /* Finally, schedule opening a new server connection. */ ctx = nfcalloc( sizeof(*ctx) ); ctx->driver = &imap_driver; ctx->ref_count = 1; socket_init( &ctx->conn, &srvc->sconf, (void (*)( void * ))imap_invoke_bad_callback, imap_socket_read, (void (*)(void *))flush_imap_cmds, ctx ); ctx->in_progress_append = &ctx->in_progress; ctx->pending_append = &ctx->pending; ctx->wait_check_append = &ctx->wait_check; gotsrv: ctx->conf = cfg; gotstore: ctx->label = label; return &ctx->gen; } static void imap_connect_store( store_t *gctx, void (*cb)( int sts, void *aux ), void *aux ) { imap_store_t *ctx = (imap_store_t *)gctx; if (ctx->state == SST_GOOD) { cb( DRV_OK, aux ); } else { ctx->callbacks.imap_open = cb; ctx->callback_aux = aux; if (ctx->state == SST_HALF) imap_open_store_namespace( ctx ); else socket_connect( &ctx->conn, imap_open_store_connected ); } } static void imap_open_store_connected( int ok, void *aux ) { imap_store_t *ctx = (imap_store_t *)aux; if (!ok) imap_open_store_bail( ctx, FAIL_WAIT ); #ifdef HAVE_LIBSSL else if (ctx->conf->server->ssl_type == SSL_IMAPS) socket_start_tls( &ctx->conn, imap_open_store_tlsstarted1 ); #endif else socket_expect_activity( &ctx->conn, 1 ); } #ifdef HAVE_LIBSSL static void imap_open_store_tlsstarted1( int ok, void *aux ) { imap_store_t *ctx = (imap_store_t *)aux; if (!ok) imap_open_store_ssl_bail( ctx ); else socket_expect_activity( &ctx->conn, 1 ); } #endif static void imap_open_store_greeted( imap_store_t *ctx ) { socket_expect_activity( &ctx->conn, 0 ); if (!ctx->caps) imap_exec( ctx, NULL, imap_open_store_p2, "CAPABILITY" ); else imap_open_store_authenticate( ctx ); } static void imap_open_store_p2( imap_store_t *ctx, imap_cmd_t *cmd ATTR_UNUSED, int response ) { if (response == RESP_NO) imap_open_store_bail( ctx, FAIL_FINAL ); else if (response == RESP_OK) imap_open_store_authenticate( ctx ); } static void imap_open_store_authenticate( imap_store_t *ctx ) { #ifdef HAVE_LIBSSL imap_server_conf_t *srvc = ctx->conf->server; #endif if (ctx->greeting != GreetingPreauth) { #ifdef HAVE_LIBSSL if (srvc->ssl_type == SSL_STARTTLS) { if (CAP(STARTTLS)) { imap_exec( ctx, NULL, imap_open_store_authenticate_p2, "STARTTLS" ); return; } else { error( "IMAP error: SSL support not available\n" ); imap_open_store_bail( ctx, FAIL_FINAL ); return; } } #endif imap_open_store_authenticate2( ctx ); } else { #ifdef HAVE_LIBSSL if (srvc->ssl_type == SSL_STARTTLS) { error( "IMAP error: SSL support not available\n" ); imap_open_store_bail( ctx, FAIL_FINAL ); return; } #endif imap_open_store_compress( ctx ); } } #ifdef HAVE_LIBSSL static void imap_open_store_authenticate_p2( imap_store_t *ctx, imap_cmd_t *cmd ATTR_UNUSED, int response ) { if (response == RESP_NO) imap_open_store_bail( ctx, FAIL_FINAL ); else if (response == RESP_OK) socket_start_tls( &ctx->conn, imap_open_store_tlsstarted2 ); } static void imap_open_store_tlsstarted2( int ok, void *aux ) { imap_store_t *ctx = (imap_store_t *)aux; if (!ok) imap_open_store_ssl_bail( ctx ); else imap_exec( ctx, NULL, imap_open_store_authenticate_p3, "CAPABILITY" ); } static void imap_open_store_authenticate_p3( imap_store_t *ctx, imap_cmd_t *cmd ATTR_UNUSED, int response ) { if (response == RESP_NO) imap_open_store_bail( ctx, FAIL_FINAL ); else if (response == RESP_OK) imap_open_store_authenticate2( ctx ); } #endif static char * cred_from_cmd( const char *cred, const char *cmd, const char *srv_name ) { FILE *fp; int ret; char buffer[8192]; // Hopefully more than enough room for XOAUTH2, etc. tokens if (*cmd == '+') { flushn(); cmd++; } if (!(fp = popen( cmd, "r" ))) { pipeerr: sys_error( "Skipping account %s, %s failed", srv_name, cred ); return NULL; } if (!fgets( buffer, sizeof(buffer), fp )) buffer[0] = 0; if ((ret = pclose( fp )) < 0) goto pipeerr; if (ret) { if (WIFSIGNALED( ret )) error( "Skipping account %s, %s crashed\n", srv_name, cred ); else error( "Skipping account %s, %s exited with status %d\n", srv_name, cred, WEXITSTATUS( ret ) ); return NULL; } if (!buffer[0]) { error( "Skipping account %s, %s produced no output\n", srv_name, cred ); return NULL; } buffer[strcspn( buffer, "\n" )] = 0; /* Strip trailing newline */ return nfstrdup( buffer ); } static const char * ensure_user( imap_server_conf_t *srvc ) { if (!srvc->user) { if (srvc->user_cmd) { srvc->user = cred_from_cmd( "UserCmd", srvc->user_cmd, srvc->name ); } else { error( "Skipping account %s, no user\n", srvc->name ); } } return srvc->user; } static const char * ensure_password( imap_server_conf_t *srvc ) { if (!srvc->pass) { if (srvc->pass_cmd) { srvc->pass = cred_from_cmd( "PassCmd", srvc->pass_cmd, srvc->name ); #ifdef HAVE_MACOS_KEYCHAIN } else if (srvc->use_keychain) { void *password_data; UInt32 password_length; OSStatus ret = SecKeychainFindInternetPassword( NULL, // keychainOrArray strlen( srvc->sconf.host ), srvc->sconf.host, 0, NULL, // securityDomain strlen( srvc->user ), srvc->user, 0, NULL, // path 0, // port - we could use it, but it seems pointless kSecProtocolTypeIMAP, kSecAuthenticationTypeDefault, &password_length, &password_data, NULL ); // itemRef if (ret != errSecSuccess) { CFStringRef errmsg = SecCopyErrorMessageString( ret, NULL ); error( "Looking up Keychain failed: %s\n", CFStringGetCStringPtr( errmsg, kCFStringEncodingUTF8 ) ); CFRelease( errmsg ); return NULL; } srvc->pass = nfstrndup( password_data, password_length ); SecKeychainItemFreeContent( NULL, password_data ); #endif /* HAVE_MACOS_KEYCHAIN */ } else { flushn(); char prompt[80]; sprintf( prompt, "Password (%s): ", srvc->name ); char *pass = getpass( prompt ); if (!pass) { perror( "getpass" ); exit( 1 ); } if (!*pass) { error( "Skipping account %s, no password\n", srvc->name ); return NULL; } /* getpass() returns a pointer to a static buffer. Make a copy for long term storage. */ srvc->pass = nfstrdup( pass ); } } return srvc->pass; } #ifdef HAVE_LIBSASL static sasl_callback_t sasl_callbacks[] = { { SASL_CB_USER, NULL, NULL }, { SASL_CB_AUTHNAME, NULL, NULL }, { SASL_CB_PASS, NULL, NULL }, { SASL_CB_LIST_END, NULL, NULL } }; static int process_sasl_interact( sasl_interact_t *interact, imap_server_conf_t *srvc ) { const char *val; for (;; ++interact) { switch (interact->id) { case SASL_CB_LIST_END: return 0; case SASL_CB_USER: // aka authorization id - who to act as case SASL_CB_AUTHNAME: // who is really logging in val = ensure_user( srvc ); break; case SASL_CB_PASS: val = ensure_password( srvc ); break; default: error( "Error: Unknown SASL interaction ID\n" ); return -1; } if (!val) return -1; interact->result = val; interact->len = strlen( val ); } } static int process_sasl_step( imap_store_t *ctx, int rc, const char *in, uint in_len, sasl_interact_t *interact, const char **out, uint *out_len ) { imap_server_conf_t *srvc = ctx->conf->server; while (rc == SASL_INTERACT) { if (process_sasl_interact( interact, srvc ) < 0) return -1; rc = sasl_client_step( ctx->sasl, in, in_len, &interact, out, out_len ); } if (rc == SASL_CONTINUE) { ctx->sasl_cont = 1; } else if (rc == SASL_OK) { ctx->sasl_cont = 0; } else { error( "Error performing SASL authentication step: %s\n", sasl_errdetail( ctx->sasl ) ); return -1; } return 0; } static int decode_sasl_data( const char *prompt, char **in, uint *in_len ) { if (prompt) { int rc; uint prompt_len = strlen( prompt ); /* We're decoding, the output will be shorter than prompt_len. */ *in = nfmalloc( prompt_len ); rc = sasl_decode64( prompt, prompt_len, *in, prompt_len, in_len ); if (rc != SASL_OK) { free( *in ); error( "Error decoding SASL prompt: %s\n", sasl_errstring( rc, NULL, NULL ) ); return -1; } } else { *in = NULL; *in_len = 0; } return 0; } static int encode_sasl_data( const char *out, uint out_len, char **enc, uint *enc_len ) { int rc; uint enc_len_max = ((out_len + 2) / 3) * 4 + 1; *enc = nfmalloc( enc_len_max ); rc = sasl_encode64( out, out_len, *enc, enc_len_max, enc_len ); if (rc != SASL_OK) { free( *enc ); error( "Error encoding SASL response: %s\n", sasl_errstring( rc, NULL, NULL ) ); return -1; } return 0; } static int do_sasl_auth( imap_store_t *ctx, imap_cmd_t *cmdp ATTR_UNUSED, const char *prompt ) { int rc, ret, iovcnt = 0; uint in_len, out_len, enc_len; const char *out; char *in, *enc; sasl_interact_t *interact = NULL; conn_iovec_t iov[2]; if (!ctx->sasl_cont) { error( "Error: IMAP wants more steps despite successful SASL authentication.\n" ); goto bail; } if (decode_sasl_data( prompt, &in, &in_len ) < 0) goto bail; rc = sasl_client_step( ctx->sasl, in, in_len, &interact, &out, &out_len ); ret = process_sasl_step( ctx, rc, in, in_len, interact, &out, &out_len ); free( in ); if (ret < 0) goto bail; if (out) { if (encode_sasl_data( out, out_len, &enc, &enc_len ) < 0) goto bail; iov[0].buf = enc; iov[0].len = enc_len; iov[0].takeOwn = GiveOwn; iovcnt = 1; if (DFlags & DEBUG_NET) { printf( "%s>+> %s\n", ctx->label, enc ); fflush( stdout ); } } else { if (DFlags & DEBUG_NET) { printf( "%s>+>\n", ctx->label ); fflush( stdout ); } } iov[iovcnt].buf = "\r\n"; iov[iovcnt].len = 2; iov[iovcnt].takeOwn = KeepOwn; iovcnt++; socket_write( &ctx->conn, iov, iovcnt ); return 0; bail: imap_open_store_bail( ctx, FAIL_FINAL ); return -1; } static void done_sasl_auth( imap_store_t *ctx, imap_cmd_t *cmd ATTR_UNUSED, int response ) { if (response == RESP_OK && ctx->sasl_cont) { sasl_interact_t *interact = NULL; const char *out; uint out_len; int rc = sasl_client_step( ctx->sasl, NULL, 0, &interact, &out, &out_len ); if (process_sasl_step( ctx, rc, NULL, 0, interact, &out, &out_len ) < 0) warn( "Warning: SASL reported failure despite successful IMAP authentication. Ignoring...\n" ); else if (out_len > 0) warn( "Warning: SASL wants more steps despite successful IMAP authentication. Ignoring...\n" ); } imap_open_store_authenticate2_p2( ctx, NULL, response ); } #endif static void imap_open_store_authenticate2( imap_store_t *ctx ) { imap_server_conf_t *srvc = ctx->conf->server; string_list_t *mech, *cmech; int auth_login = 0; int skipped_login = 0; #ifdef HAVE_LIBSASL const char *saslavail; char saslmechs[1024], *saslend = saslmechs; int want_external = 0; #endif // Ensure that there are no leftovers from previous runs. This is needed in case // the credentials have a timing dependency or otherwise lose validity after use. if (srvc->user_cmd) { free( srvc->user ); srvc->user = NULL; } if (srvc->pass_cmd) { free( srvc->pass ); srvc->pass = NULL; } info( "Logging in...\n" ); for (mech = srvc->auth_mechs; mech; mech = mech->next) { int any = !strcmp( mech->string, "*" ); for (cmech = ctx->auth_mechs; cmech; cmech = cmech->next) { if (any || !strcasecmp( mech->string, cmech->string )) { if (!strcasecmp( cmech->string, "LOGIN" )) { #ifdef HAVE_LIBSSL if (ctx->conn.ssl || !any) #else if (!any) #endif auth_login = 1; else skipped_login = 1; #ifdef HAVE_LIBSASL } else { uint len = strlen( cmech->string ); if (saslend + len + 2 > saslmechs + sizeof(saslmechs)) oob(); *saslend++ = ' '; memcpy( saslend, cmech->string, len + 1 ); saslend += len; if (!strcasecmp( cmech->string, "EXTERNAL" )) want_external = 1; #endif } } } } #ifdef HAVE_LIBSASL if (saslend != saslmechs) { int rc; uint out_len = 0; char *enc = NULL; const char *gotmech = NULL, *out = NULL; sasl_interact_t *interact = NULL; imap_cmd_t *cmd; static int sasl_inited; if (!sasl_inited) { rc = sasl_client_init( sasl_callbacks ); if (rc != SASL_OK) { saslbail: error( "Error initializing SASL client: %s\n", sasl_errstring( rc, NULL, NULL ) ); goto bail; } sasl_inited = 1; } rc = sasl_client_new( "imap", srvc->sconf.host, NULL, NULL, NULL, 0, &ctx->sasl ); if (rc != SASL_OK) { if (rc == SASL_NOMECH) goto notsasl; if (!ctx->sasl) goto saslbail; error( "Error initializing SASL context: %s\n", sasl_errdetail( ctx->sasl ) ); goto bail; } // The built-in EXTERNAL mechanism wants the authentication id to be set // even before instantiation; consequently it won't prompt for it, either. // While this clearly makes sense on the server side, it arguably does not // on the client side. Ah, well ... if (want_external && ensure_user( srvc )) { rc = sasl_setprop( ctx->sasl, SASL_AUTH_EXTERNAL, srvc->user ); if (rc != SASL_OK ) { error( "Error setting SASL authentication id: %s\n", sasl_errdetail( ctx->sasl ) ); goto bail; } } rc = sasl_client_start( ctx->sasl, saslmechs + 1, &interact, CAP(SASLIR) ? &out : NULL, &out_len, &gotmech ); if (rc == SASL_NOMECH) goto notsasl; if (gotmech) info( "Authenticating with SASL mechanism %s...\n", gotmech ); /* Technically, we are supposed to loop over sasl_client_start(), * but it just calls sasl_client_step() anyway. */ if (process_sasl_step( ctx, rc, NULL, 0, interact, CAP(SASLIR) ? &out : NULL, &out_len ) < 0) goto bail; if (out) { if (!out_len) enc = nfstrdup( "=" ); /* A zero-length initial response is encoded as padding. */ else if (encode_sasl_data( out, out_len, &enc, NULL ) < 0) goto bail; } cmd = new_imap_cmd( sizeof(*cmd) ); cmd->param.cont = do_sasl_auth; imap_exec( ctx, cmd, done_sasl_auth, enc ? "AUTHENTICATE %s %s" : "AUTHENTICATE %s", gotmech, enc ); free( enc ); return; notsasl: if (!ctx->sasl || sasl_listmech( ctx->sasl, NULL, "", " ", "", &saslavail, NULL, NULL ) != SASL_OK) saslavail = "(none)"; if (!auth_login) { error( "IMAP error: selected SASL mechanism(s) not available;\n" " selected:%s\n available: %s\n", saslmechs, saslavail ); goto skipnote; } info( "NOT using available SASL mechanism(s): %s\n", saslavail ); sasl_dispose( &ctx->sasl ); } #endif if (auth_login) { if (!ensure_user( srvc ) || !ensure_password( srvc )) goto bail; #ifdef HAVE_LIBSSL if (!ctx->conn.ssl) #endif warn( "*** IMAP Warning *** Password is being sent in the clear\n" ); imap_exec( ctx, NULL, imap_open_store_authenticate2_p2, "LOGIN \"%\\s\" \"%\\s\"", srvc->user, srvc->pass ); return; } error( "IMAP error: server supports no acceptable authentication mechanism\n" ); #ifdef HAVE_LIBSASL skipnote: #endif if (skipped_login) error( "Note: not using LOGIN because connection is not encrypted;\n" " use 'AuthMechs LOGIN' explicitly to force it.\n" ); bail: imap_open_store_bail( ctx, FAIL_FINAL ); } static void imap_open_store_authenticate2_p2( imap_store_t *ctx, imap_cmd_t *cmd ATTR_UNUSED, int response ) { if (response == RESP_NO) imap_open_store_bail( ctx, FAIL_FINAL ); else if (response == RESP_OK) imap_open_store_compress( ctx ); } static void imap_open_store_compress( imap_store_t *ctx ) { #ifdef HAVE_LIBZ if (CAP(COMPRESS_DEFLATE)) { imap_exec( ctx, NULL, imap_open_store_compress_p2, "COMPRESS DEFLATE" ); return; } #endif imap_open_store_namespace( ctx ); } #ifdef HAVE_LIBZ static void imap_open_store_compress_p2( imap_store_t *ctx, imap_cmd_t *cmd ATTR_UNUSED, int response ) { if (response == RESP_NO) { /* We already reported an error, but it's not fatal to us. */ imap_open_store_namespace( ctx ); } else if (response == RESP_OK) { socket_start_deflate( &ctx->conn ); imap_open_store_namespace( ctx ); } } #endif static void imap_open_store_namespace( imap_store_t *ctx ) { imap_store_conf_t *cfg = ctx->conf; ctx->state = SST_HALF; ctx->prefix = cfg->path; ctx->delimiter[0] = cfg->delimiter; if (((!ctx->prefix && cfg->use_namespace) || !cfg->delimiter) && CAP(NAMESPACE)) { /* get NAMESPACE info */ if (!ctx->got_namespace) imap_exec( ctx, NULL, imap_open_store_namespace_p2, "NAMESPACE" ); else imap_open_store_namespace2( ctx ); return; } imap_open_store_finalize( ctx ); } static void imap_open_store_namespace_p2( imap_store_t *ctx, imap_cmd_t *cmd ATTR_UNUSED, int response ) { if (response == RESP_NO) { imap_open_store_bail( ctx, FAIL_FINAL ); } else if (response == RESP_OK) { ctx->got_namespace = 1; imap_open_store_namespace2( ctx ); } } static void imap_open_store_namespace2( imap_store_t *ctx ) { if (!ctx->prefix && ctx->conf->use_namespace) ctx->prefix = ctx->ns_prefix; if (!ctx->delimiter[0]) ctx->delimiter[0] = ctx->ns_delimiter; imap_open_store_finalize( ctx ); } static void imap_open_store_finalize( imap_store_t *ctx ) { ctx->state = SST_GOOD; if (!ctx->prefix) ctx->prefix = ""; else normalize_INBOX( ctx, ctx->prefix, -1 ); ctx->trashnc = TrashUnknown; ctx->callbacks.imap_open( DRV_OK, ctx->callback_aux ); } #ifdef HAVE_LIBSSL static void imap_open_store_ssl_bail( imap_store_t *ctx ) { /* This avoids that we try to send LOGOUT to an unusable socket. */ socket_close( &ctx->conn ); imap_open_store_bail( ctx, FAIL_FINAL ); } #endif static void imap_open_store_bail( imap_store_t *ctx, int failed ) { ctx->conf->server->failed = (char)failed; ctx->callbacks.imap_open( DRV_STORE_BAD, ctx->callback_aux ); } /******************* imap_open_box *******************/ static int imap_select_box( store_t *gctx, const char *name ) { imap_store_t *ctx = (imap_store_t *)gctx; assert( !ctx->pending && !ctx->in_progress && !ctx->wait_check ); free_generic_messages( &ctx->msgs->gen ); ctx->msgs = NULL; ctx->msgapp = &ctx->msgs; ctx->name = name; return DRV_OK; } static const char * imap_get_box_path( store_t *gctx ATTR_UNUSED ) { return NULL; } typedef union { imap_cmd_t gen; struct { IMAP_CMD void (*callback)( int sts, uint uidvalidity, void *aux ); void *callback_aux; }; } imap_cmd_open_box_t; static void imap_open_box_p2( imap_store_t *, imap_cmd_t *, int ); static void imap_open_box_p3( imap_store_t *, imap_cmd_t *, int ); static void imap_open_box_p4( imap_store_t *, imap_cmd_open_box_t *, int ); static void imap_open_box( store_t *gctx, void (*cb)( int sts, uint uidvalidity, void *aux ), void *aux ) { imap_store_t *ctx = (imap_store_t *)gctx; imap_cmd_open_box_t *cmd; char *buf; if (prepare_box( &buf, ctx ) < 0) { cb( DRV_BOX_BAD, UIDVAL_BAD, aux ); return; } ctx->uidvalidity = UIDVAL_BAD; ctx->uidnext = 0; INIT_IMAP_CMD(imap_cmd_open_box_t, cmd, cb, aux) cmd->param.failok = 1; imap_exec( ctx, &cmd->gen, imap_open_box_p2, "SELECT \"%\\s\"", buf ); free( buf ); } static void imap_open_box_p2( imap_store_t *ctx, imap_cmd_t *gcmd, int response ) { imap_cmd_open_box_t *cmdp = (imap_cmd_open_box_t *)gcmd; imap_cmd_open_box_t *cmd; if (response != RESP_OK || ctx->uidnext) { imap_open_box_p4( ctx, cmdp, response ); return; } assert( ctx->fetch_sts == FetchNone ); ctx->fetch_sts = FetchUidNext; INIT_IMAP_CMD(imap_cmd_open_box_t, cmd, cmdp->callback, cmdp->callback_aux) imap_exec( ctx, &cmd->gen, imap_open_box_p3, "UID FETCH * (UID)" ); } static void imap_open_box_p3( imap_store_t *ctx, imap_cmd_t *gcmd, int response ) { imap_cmd_open_box_t *cmdp = (imap_cmd_open_box_t *)gcmd; ctx->fetch_sts = FetchNone; if (!ctx->uidnext) { if (ctx->total_msgs) { error( "IMAP error: querying server for highest UID failed\n" ); imap_open_box_p4( ctx, cmdp, RESP_NO ); return; } // This is ok, the box is simply empty. ctx->uidnext = 1; } imap_open_box_p4( ctx, cmdp, response ); } static void imap_open_box_p4( imap_store_t *ctx, imap_cmd_open_box_t *cmdp, int response ) { transform_box_response( &response ); cmdp->callback( response, ctx->uidvalidity, cmdp->callback_aux ); } static uint imap_get_uidnext( store_t *gctx ) { imap_store_t *ctx = (imap_store_t *)gctx; return ctx->uidnext; } static xint imap_get_supported_flags( store_t *gctx ) { imap_store_t *ctx = (imap_store_t *)gctx; return ctx->has_forwarded ? 255 : (255 & ~F_FORWARDED); } /******************* imap_create_box *******************/ static void imap_create_box( store_t *gctx, void (*cb)( int sts, void *aux ), void *aux ) { imap_store_t *ctx = (imap_store_t *)gctx; imap_cmd_simple_t *cmd; char *buf; if (prepare_box( &buf, ctx ) < 0) { cb( DRV_BOX_BAD, aux ); return; } INIT_IMAP_CMD(imap_cmd_simple_t, cmd, cb, aux) imap_exec( ctx, &cmd->gen, imap_done_simple_box, "CREATE \"%\\s\"", buf ); free( buf ); } /******************* imap_delete_box *******************/ static int imap_confirm_box_empty( store_t *gctx ) { imap_store_t *ctx = (imap_store_t *)gctx; return ctx->total_msgs ? DRV_BOX_BAD : DRV_OK; } static void imap_delete_box_p2( imap_store_t *, imap_cmd_t *, int ); static void imap_delete_box( store_t *gctx, void (*cb)( int sts, void *aux ), void *aux ) { imap_store_t *ctx = (imap_store_t *)gctx; imap_cmd_simple_t *cmd; INIT_IMAP_CMD(imap_cmd_simple_t, cmd, cb, aux) imap_exec( ctx, &cmd->gen, imap_delete_box_p2, "CLOSE" ); } static void imap_delete_box_p2( imap_store_t *ctx, imap_cmd_t *gcmd, int response ) { imap_cmd_simple_t *cmdp = (imap_cmd_simple_t *)gcmd; imap_cmd_simple_t *cmd; char *buf; if (response != RESP_OK) { imap_done_simple_box( ctx, &cmdp->gen, response ); return; } if (prepare_box( &buf, ctx ) < 0) { imap_done_simple_box( ctx, &cmdp->gen, RESP_NO ); return; } INIT_IMAP_CMD(imap_cmd_simple_t, cmd, cmdp->callback, cmdp->callback_aux) imap_exec( ctx, &cmd->gen, imap_done_simple_box, "DELETE \"%\\s\"", buf ); free( buf ); } static int imap_finish_delete_box( store_t *gctx ATTR_UNUSED ) { return DRV_OK; } /******************* imap_load_box *******************/ static uint imap_prepare_load_box( store_t *gctx, uint opts ) { imap_store_t *ctx = (imap_store_t *)gctx; ctx->opts = opts; return opts; } enum { WantSize = 1, WantTuids = 2, WantMsgids = 4 }; typedef struct { uint first, last; int flags; } imap_range_t; static void imap_set_range( imap_range_t *ranges, uint *nranges, int low_flags, int high_flags, uint maxlow ) { if (low_flags != high_flags) { for (uint r = 0; r < *nranges; r++) { if (ranges[r].first > maxlow) break; /* Range starts above split point; so do all subsequent ranges. */ if (ranges[r].last < maxlow) continue; /* Range ends below split point; try next one. */ if (ranges[r].last != maxlow) { /* Range does not end exactly at split point; need to split. */ memmove( &ranges[r + 1], &ranges[r], ((*nranges)++ - r) * sizeof(*ranges) ); ranges[r].last = maxlow; ranges[r + 1].first = maxlow + 1; } break; } } for (uint r = 0; r < *nranges; r++) ranges[r].flags |= (ranges[r].last <= maxlow) ? low_flags : high_flags; } typedef union { imap_cmd_refcounted_state_t gen; struct { IMAP_CMD_REFCOUNTED_STATE void (*callback)( int sts, message_t *msgs, int total_msgs, int recent_msgs, void *aux ); void *callback_aux; }; } imap_load_box_state_t; static void imap_submit_load( imap_store_t *, const char *, int, imap_load_box_state_t * ); static void imap_submit_load_p3( imap_store_t *ctx, imap_load_box_state_t * ); static void imap_load_box( store_t *gctx, uint minuid, uint maxuid, uint finduid, uint pairuid, uint newuid, uint_array_t excs, void (*cb)( int sts, message_t *msgs, int total_msgs, int recent_msgs, void *aux ), void *aux ) { imap_store_t *ctx = (imap_store_t *)gctx; char buf[1000]; if (!ctx->total_msgs) { free( excs.data ); cb( DRV_OK, NULL, 0, 0, aux ); } else { assert( ctx->fetch_sts == FetchNone ); ctx->fetch_sts = FetchMsgs; INIT_REFCOUNTED_STATE(imap_load_box_state_t, sts, cb, aux) for (uint i = 0; i < excs.size; ) { for (int bl = 0; i < excs.size && bl < 960; i++) { if (bl) buf[bl++] = ','; bl += sprintf( buf + bl, "%u", excs.data[i] ); uint j = i; for (; i + 1 < excs.size && excs.data[i + 1] == excs.data[i] + 1; i++) {} if (i != j) bl += sprintf( buf + bl, ":%u", excs.data[i] ); } imap_submit_load( ctx, buf, shifted_bit( ctx->opts, OPEN_OLD_IDS, WantMsgids ), sts ); } if (maxuid == UINT_MAX) maxuid = ctx->uidnext - 1; if (maxuid >= minuid) { imap_range_t ranges[3]; ranges[0].first = minuid; ranges[0].last = maxuid; ranges[0].flags = 0; uint nranges = 1; if (ctx->opts & OPEN_NEW_SIZE) imap_set_range( ranges, &nranges, 0, WantSize, newuid ); if (ctx->opts & OPEN_FIND) imap_set_range( ranges, &nranges, 0, WantTuids, finduid - 1 ); if (ctx->opts & OPEN_OLD_IDS) imap_set_range( ranges, &nranges, WantMsgids, 0, pairuid ); for (uint r = 0; r < nranges; r++) { sprintf( buf, "%u:%u", ranges[r].first, ranges[r].last ); imap_submit_load( ctx, buf, ranges[r].flags, sts ); } } free( excs.data ); imap_submit_load_p3( ctx, sts ); } } static int imap_sort_msgs_comp( const void *a_, const void *b_ ) { const message_t *a = *(const message_t * const *)a_; const message_t *b = *(const message_t * const *)b_; if (a->uid < b->uid) return -1; if (a->uid > b->uid) return 1; return 0; } static void imap_sort_msgs( imap_store_t *ctx ) { uint count = count_generic_messages( &ctx->msgs->gen ); if (count <= 1) return; imap_message_t **t = nfmalloc( sizeof(*t) * count ); imap_message_t *m = ctx->msgs; for (uint i = 0; i < count; i++) { t[i] = m; m = m->next; } qsort( t, count, sizeof(*t), imap_sort_msgs_comp ); ctx->msgs = t[0]; uint j; for (j = 0; j < count - 1; j++) t[j]->next = t[j + 1]; ctx->msgapp = &t[j]->next; *ctx->msgapp = NULL; free( t ); } static void imap_submit_load_p2( imap_store_t *, imap_cmd_t *, int ); static void imap_submit_load( imap_store_t *ctx, const char *buf, int flags, imap_load_box_state_t *sts ) { imap_exec( ctx, imap_refcounted_new_cmd( &sts->gen ), imap_submit_load_p2, "UID FETCH %s (UID%s%s%s%s%s%s%s)", buf, (ctx->opts & OPEN_FLAGS) ? " FLAGS" : "", (flags & WantSize) ? " RFC822.SIZE" : "", (flags & (WantTuids | WantMsgids)) ? " BODY.PEEK[HEADER.FIELDS (" : "", (flags & WantTuids) ? "X-TUID" : "", !(~flags & (WantTuids | WantMsgids)) ? " " : "", (flags & WantMsgids) ? "MESSAGE-ID" : "", (flags & (WantTuids | WantMsgids)) ? ")]" : ""); } static void imap_submit_load_p2( imap_store_t *ctx, imap_cmd_t *cmd, int response ) { imap_load_box_state_t *sts = (imap_load_box_state_t *)((imap_cmd_refcounted_t *)cmd)->state; transform_refcounted_box_response( &sts->gen, response ); imap_submit_load_p3( ctx, sts ); } static void imap_submit_load_p3( imap_store_t *ctx, imap_load_box_state_t *sts ) { DONE_REFCOUNTED_STATE_ARGS(sts, { ctx->fetch_sts = FetchNone; if (sts->ret_val == DRV_OK) imap_sort_msgs( ctx ); }, &ctx->msgs->gen, ctx->total_msgs, ctx->recent_msgs) } /******************* imap_fetch_msg *******************/ static void imap_fetch_msg_p2( imap_store_t *, imap_cmd_t *, int ); static void imap_fetch_msg( store_t *ctx, message_t *msg, msg_data_t *data, int minimal, void (*cb)( int sts, void *aux ), void *aux ) { imap_cmd_fetch_msg_t *cmd; INIT_IMAP_CMD_X(imap_cmd_fetch_msg_t, cmd, cb, aux) cmd->param.uid = msg->uid; cmd->msg_data = data; data->data = NULL; imap_exec( (imap_store_t *)ctx, &cmd->gen.gen, imap_fetch_msg_p2, "UID FETCH %u (%s%sBODY.PEEK[%s])", msg->uid, !(msg->status & M_FLAGS) ? "FLAGS " : "", (data->date== -1) ? "INTERNALDATE " : "", minimal ? "HEADER" : "" ); } static void imap_fetch_msg_p2( imap_store_t *ctx, imap_cmd_t *gcmd, int response ) { imap_cmd_fetch_msg_t *cmd = (imap_cmd_fetch_msg_t *)gcmd; if (response == RESP_OK && !cmd->msg_data->data) { /* The FETCH succeeded, but there is no message with this UID. */ response = RESP_NO; } imap_done_simple_msg( ctx, gcmd, response ); } /******************* imap_set_msg_flags *******************/ static uint imap_make_flags( int flags, char *buf ) { const char *s; uint i, d; for (i = d = 0; i < as(Flags); i++) if (flags & (1 << i)) { buf[d++] = ' '; for (s = Flags[i]; *s; s++) buf[d++] = *s; } buf[0] = '('; buf[d++] = ')'; return d; } typedef union { imap_cmd_refcounted_state_t gen; struct { IMAP_CMD_REFCOUNTED_STATE void (*callback)( int sts, void *aux ); void *callback_aux; }; } imap_set_msg_flags_state_t; static void imap_set_flags_p2( imap_store_t *, imap_cmd_t *, int ); static void imap_set_flags_p3( imap_set_msg_flags_state_t * ); static void imap_flags_helper( imap_store_t *ctx, uint uid, char what, int flags, imap_set_msg_flags_state_t *sts ) { char buf[256]; buf[imap_make_flags( flags, buf )] = 0; imap_cmd_t *cmd = imap_refcounted_new_cmd( &sts->gen ); cmd->param.wait_check = 1; imap_exec( ctx, cmd, imap_set_flags_p2, "UID STORE %u %cFLAGS.SILENT %s", uid, what, buf ); } static void imap_set_msg_flags( store_t *gctx, message_t *msg, uint uid, int add, int del, void (*cb)( int sts, void *aux ), void *aux ) { imap_store_t *ctx = (imap_store_t *)gctx; if (msg) { uid = msg->uid; add &= ~msg->flags; del &= msg->flags; msg->flags |= add; msg->flags &= ~del; } if (add || del) { INIT_REFCOUNTED_STATE(imap_set_msg_flags_state_t, sts, cb, aux) if (add) imap_flags_helper( ctx, uid, '+', add, sts ); if (del) imap_flags_helper( ctx, uid, '-', del, sts ); imap_set_flags_p3( sts ); } else { cb( DRV_OK, aux ); } } static void imap_set_flags_p2( imap_store_t *ctx ATTR_UNUSED, imap_cmd_t *cmd, int response ) { imap_set_msg_flags_state_t *sts = (imap_set_msg_flags_state_t *)((imap_cmd_refcounted_t *)cmd)->state; transform_refcounted_msg_response( &sts->gen, response); imap_set_flags_p3( sts ); } static void imap_set_flags_p3( imap_set_msg_flags_state_t *sts ) { DONE_REFCOUNTED_STATE(sts) } /******************* imap_close_box *******************/ typedef union { imap_cmd_refcounted_state_t gen; struct { IMAP_CMD_REFCOUNTED_STATE void (*callback)( int sts, void *aux ); void *callback_aux; }; } imap_expunge_state_t; static void imap_close_box_p2( imap_store_t *, imap_cmd_t *, int ); static void imap_close_box_p3( imap_expunge_state_t * ); static void imap_close_box( store_t *gctx, void (*cb)( int sts, void *aux ), void *aux ) { imap_store_t *ctx = (imap_store_t *)gctx; assert( !ctx->num_wait_check ); if (ctx->conf->trash && CAP(UIDPLUS)) { INIT_REFCOUNTED_STATE(imap_expunge_state_t, sts, cb, aux) imap_message_t *msg, *fmsg, *nmsg; int bl; char buf[1000]; for (msg = ctx->msgs; ; ) { for (bl = 0; msg && bl < 960; msg = msg->next) { if (!(msg->flags & F_DELETED)) continue; if (bl) buf[bl++] = ','; bl += sprintf( buf + bl, "%u", msg->uid ); fmsg = msg; for (; (nmsg = msg->next) && (nmsg->flags & F_DELETED); msg = nmsg) {} if (msg != fmsg) bl += sprintf( buf + bl, ":%u", msg->uid ); } if (!bl) break; imap_exec( ctx, imap_refcounted_new_cmd( &sts->gen ), imap_close_box_p2, "UID EXPUNGE %s", buf ); } imap_close_box_p3( sts ); } else { /* This is inherently racy: it may cause messages which other clients * marked as deleted to be expunged without being trashed. */ imap_cmd_simple_t *cmd; INIT_IMAP_CMD(imap_cmd_simple_t, cmd, cb, aux) imap_exec( ctx, &cmd->gen, imap_done_simple_box, "CLOSE" ); } } static void imap_close_box_p2( imap_store_t *ctx ATTR_UNUSED, imap_cmd_t *cmd, int response ) { imap_expunge_state_t *sts = (imap_expunge_state_t *)((imap_cmd_refcounted_t *)cmd)->state; transform_refcounted_box_response( &sts->gen, response ); imap_close_box_p3( sts ); } static void imap_close_box_p3( imap_expunge_state_t *sts ) { DONE_REFCOUNTED_STATE(sts) } /******************* imap_trash_msg *******************/ static void imap_trash_msg( store_t *gctx, message_t *msg, void (*cb)( int sts, void *aux ), void *aux ) { imap_store_t *ctx = (imap_store_t *)gctx; imap_cmd_simple_t *cmd; char *buf; INIT_IMAP_CMD(imap_cmd_simple_t, cmd, cb, aux) cmd->param.create = 1; cmd->param.to_trash = 1; if (prepare_trash( &buf, ctx ) < 0) { cb( DRV_BOX_BAD, aux ); return; } imap_exec( ctx, &cmd->gen, imap_done_simple_msg, CAP(MOVE) ? "UID MOVE %u \"%\\s\"" : "UID COPY %u \"%\\s\"", msg->uid, buf ); free( buf ); } /******************* imap_store_msg *******************/ static void imap_store_msg_p2( imap_store_t *, imap_cmd_t *, int ); static void imap_store_msg( store_t *gctx, msg_data_t *data, int to_trash, void (*cb)( int sts, uint uid, void *aux ), void *aux ) { imap_store_t *ctx = (imap_store_t *)gctx; imap_cmd_out_uid_t *cmd; char *buf; uint d; char flagstr[128], datestr[64]; d = 0; if (data->flags) { d = imap_make_flags( data->flags, flagstr ); flagstr[d++] = ' '; } flagstr[d] = 0; INIT_IMAP_CMD(imap_cmd_out_uid_t, cmd, cb, aux) ctx->buffer_mem += data->len; cmd->param.data_len = data->len; cmd->param.data = data->data; if (to_trash) { cmd->param.create = 1; cmd->param.to_trash = 1; if (prepare_trash( &buf, ctx ) < 0) { cb( DRV_BOX_BAD, 0, aux ); return; } } else { if (prepare_box( &buf, ctx ) < 0) { cb( DRV_BOX_BAD, 0, aux ); return; } } if (data->date) { /* configure ensures that %z actually works. */ DIAG_PUSH DIAG_DISABLE("-Wformat") strftime( datestr, sizeof(datestr), "%d-%b-%Y %H:%M:%S %z", localtime( &data->date ) ); DIAG_POP imap_exec( ctx, &cmd->gen, imap_store_msg_p2, "APPEND \"%\\s\" %s\"%\\s\" ", buf, flagstr, datestr ); } else { imap_exec( ctx, &cmd->gen, imap_store_msg_p2, "APPEND \"%\\s\" %s", buf, flagstr ); } free( buf ); } static void imap_store_msg_p2( imap_store_t *ctx ATTR_UNUSED, imap_cmd_t *cmd, int response ) { imap_cmd_out_uid_t *cmdp = (imap_cmd_out_uid_t *)cmd; transform_msg_response( &response ); cmdp->callback( response, cmdp->param.uid, cmdp->callback_aux ); } /******************* imap_find_new_msgs *******************/ static void imap_find_new_msgs_p2( imap_store_t *, imap_cmd_t *, int ); static void imap_find_new_msgs_p3( imap_store_t *, imap_cmd_t *, int ); static void imap_find_new_msgs_p4( imap_store_t *, imap_cmd_t *, int ); static void imap_find_new_msgs( store_t *gctx, uint newuid, void (*cb)( int sts, message_t *msgs, void *aux ), void *aux ) { imap_store_t *ctx = (imap_store_t *)gctx; imap_cmd_find_new_t *cmd; INIT_IMAP_CMD(imap_cmd_find_new_t, cmd, cb, aux) cmd->out_msgs = ctx->msgapp; cmd->uid = newuid; // Some servers fail to enumerate recently STOREd messages without syncing first. imap_exec( (imap_store_t *)ctx, &cmd->gen, imap_find_new_msgs_p2, "CHECK" ); } static void imap_find_new_msgs_p2( imap_store_t *ctx, imap_cmd_t *gcmd, int response ) { imap_cmd_find_new_t *cmdp = (imap_cmd_find_new_t *)gcmd; imap_cmd_find_new_t *cmd; if (response != RESP_OK) { imap_done_simple_box( ctx, gcmd, response ); return; } // We appended messages, so we need to re-query UIDNEXT. ctx->uidnext = 0; assert( ctx->fetch_sts == FetchNone ); ctx->fetch_sts = FetchUidNext; INIT_IMAP_CMD(imap_cmd_find_new_t, cmd, cmdp->callback, cmdp->callback_aux) cmd->out_msgs = cmdp->out_msgs; cmd->uid = cmdp->uid; imap_exec( ctx, &cmd->gen, imap_find_new_msgs_p3, "UID FETCH * (UID)" ); } static void imap_find_new_msgs_p3( imap_store_t *ctx, imap_cmd_t *gcmd, int response ) { imap_cmd_find_new_t *cmdp = (imap_cmd_find_new_t *)gcmd; imap_cmd_find_new_t *cmd; ctx->fetch_sts = FetchNone; if (response != RESP_OK) { imap_find_new_msgs_p4( ctx, gcmd, response ); return; } if (ctx->uidnext <= cmdp->uid) { if (!ctx->uidnext && ctx->total_msgs) { error( "IMAP error: re-querying server for highest UID failed\n" ); imap_find_new_msgs_p4( ctx, gcmd, RESP_NO ); } else { // The messages evaporated, or the server just didn't register them - // we'll catch that later (via lost TUIDs). // This case is why we do the extra roundtrip instead of simply passing // '*' as the end of the range below - IMAP ranges are unordered, so we // would potentially re-fetch an already loaded message. imap_find_new_msgs_p4( ctx, gcmd, RESP_OK ); } return; } INIT_IMAP_CMD(imap_cmd_find_new_t, cmd, cmdp->callback, cmdp->callback_aux) cmd->out_msgs = cmdp->out_msgs; imap_exec( (imap_store_t *)ctx, &cmd->gen, imap_find_new_msgs_p4, "UID FETCH %u:%u (UID BODY.PEEK[HEADER.FIELDS (X-TUID)])", cmdp->uid, ctx->uidnext - 1 ); } static void imap_find_new_msgs_p4( imap_store_t *ctx ATTR_UNUSED, imap_cmd_t *gcmd, int response ) { imap_cmd_find_new_t *cmdp = (imap_cmd_find_new_t *)gcmd; transform_box_response( &response ); cmdp->callback( response, &(*cmdp->out_msgs)->gen, cmdp->callback_aux ); } /******************* imap_list_store *******************/ typedef union { imap_cmd_refcounted_state_t gen; struct { IMAP_CMD_REFCOUNTED_STATE void (*callback)( int sts, string_list_t *, void *aux ); void *callback_aux; }; } imap_list_store_state_t; static void imap_list_store_p2( imap_store_t *, imap_cmd_t *, int ); static void imap_list_store_p3( imap_store_t *, imap_list_store_state_t * ); static void imap_list_store( store_t *gctx, int flags, void (*cb)( int sts, string_list_t *boxes, void *aux ), void *aux ) { imap_store_t *ctx = (imap_store_t *)gctx; imap_store_conf_t *cfg = ctx->conf; INIT_REFCOUNTED_STATE(imap_list_store_state_t, sts, cb, aux) // ctx->prefix may be empty, "INBOX.", or something else. // 'flags' may be LIST_INBOX, LIST_PATH (or LIST_PATH_MAYBE), or both. 'listed' // already containing a particular value effectively removes it from 'flags'. // This matrix determines what to query, and what comes out as a side effect. // The lowercase letters indicate unnecessary results; the queries are done // this way to have non-overlapping result sets, so subsequent calls create // no duplicates: // // qry \ pfx | empty | inbox | other // ----------+-------+-------+------- // inbox | p [I] | I [p] | I // both | P [I] | I [P] | I + P // path | P [i] | i [P] | P // int pfx_is_empty = !*ctx->prefix; int pfx_is_inbox = !pfx_is_empty && is_inbox( ctx, ctx->prefix, -1 ); if (((flags & (LIST_PATH | LIST_PATH_MAYBE)) || pfx_is_empty) && !pfx_is_inbox && !(ctx->listed & LIST_PATH)) { ctx->listed |= LIST_PATH; if (pfx_is_empty) ctx->listed |= LIST_INBOX; imap_exec( ctx, imap_refcounted_new_cmd( &sts->gen ), imap_list_store_p2, "%s \"\" \"%\\s*\"", cfg->use_lsub ? "LSUB" : "LIST", ctx->prefix ); } if (((flags & LIST_INBOX) || pfx_is_inbox) && !pfx_is_empty && !(ctx->listed & LIST_INBOX)) { ctx->listed |= LIST_INBOX; if (pfx_is_inbox) ctx->listed |= LIST_PATH; imap_exec( ctx, imap_refcounted_new_cmd( &sts->gen ), imap_list_store_p2, "%s \"\" INBOX*", cfg->use_lsub ? "LSUB" : "LIST" ); } imap_list_store_p3( ctx, sts ); } static void imap_list_store_p2( imap_store_t *ctx, imap_cmd_t *cmd, int response ) { imap_list_store_state_t *sts = (imap_list_store_state_t *)((imap_cmd_refcounted_t *)cmd)->state; transform_refcounted_box_response( &sts->gen, response ); imap_list_store_p3( ctx, sts ); } static void imap_list_store_p3( imap_store_t *ctx, imap_list_store_state_t *sts ) { DONE_REFCOUNTED_STATE_ARGS(sts, , ctx->boxes) } /******************* imap_cancel_cmds *******************/ static void imap_cancel_cmds( store_t *gctx, void (*cb)( void *aux ), void *aux ) { imap_store_t *ctx = (imap_store_t *)gctx; finalize_checked_imap_cmds( ctx, RESP_CANCEL ); cancel_pending_imap_cmds( ctx ); if (ctx->in_progress) { ctx->canceling = 1; ctx->callbacks.imap_cancel = cb; ctx->callback_aux = aux; } else { cb( aux ); } } /******************* imap_commit_cmds *******************/ static void imap_commit_cmds_p2( imap_store_t *, imap_cmd_t *, int ); static void imap_commit_cmds( store_t *gctx ) { imap_store_t *ctx = (imap_store_t *)gctx; if (ctx->num_wait_check) imap_exec( ctx, NULL, imap_commit_cmds_p2, "CHECK" ); } static void imap_commit_cmds_p2( imap_store_t *ctx, imap_cmd_t *cmd ATTR_UNUSED, int response ) { finalize_checked_imap_cmds( ctx, response ); } /******************* imap_get_memory_usage *******************/ static uint imap_get_memory_usage( store_t *gctx ) { imap_store_t *ctx = (imap_store_t *)gctx; return ctx->buffer_mem + ctx->conn.buffer_mem; } /******************* imap_get_fail_state *******************/ static int imap_get_fail_state( store_conf_t *gconf ) { return ((imap_store_conf_t *)gconf)->server->failed; } /******************* imap_parse_store *******************/ static imap_server_conf_t *servers, **serverapp = &servers; static int imap_parse_store( conffile_t *cfg, store_conf_t **storep ) { imap_store_conf_t *store; imap_server_conf_t *server, *srv, sserver; const char *type, *name, *arg; unsigned u; int acc_opt = 0; #ifdef HAVE_LIBSSL /* Legacy SSL options */ int require_ssl = -1, use_imaps = -1; int use_tlsv1 = -1, use_tlsv11 = -1, use_tlsv12 = -1, use_tlsv13 = -1; #endif /* Legacy SASL option */ int require_cram = -1; if (!strcasecmp( "IMAPAccount", cfg->cmd )) { server = nfcalloc( sizeof(*server) ); name = server->name = nfstrdup( cfg->val ); *serverapp = server; serverapp = &server->next; store = NULL; *storep = NULL; type = "IMAP account"; } else if (!strcasecmp( "IMAPStore", cfg->cmd )) { store = nfcalloc( sizeof(*store) ); store->driver = &imap_driver; name = store->name = nfstrdup( cfg->val ); store->use_namespace = 1; *storep = &store->gen; memset( &sserver, 0, sizeof(sserver) ); server = &sserver; type = "IMAP store"; } else return 0; server->sconf.timeout = 20; #ifdef HAVE_LIBSSL server->ssl_type = -1; server->sconf.ssl_versions = -1; server->sconf.system_certs = 1; #endif server->max_in_progress = INT_MAX; while (getcline( cfg ) && cfg->cmd) { if (!strcasecmp( "Host", cfg->cmd )) { /* The imap[s]: syntax is just a backwards compat hack. */ arg = cfg->val; #ifdef HAVE_LIBSSL if (starts_with( arg, -1, "imaps:", 6 )) { arg += 6; server->ssl_type = SSL_IMAPS; if (server->sconf.ssl_versions == -1) server->sconf.ssl_versions = TLSv1 | TLSv1_1 | TLSv1_2 | TLSv1_3; } else #endif if (starts_with( arg, -1, "imap:", 5 )) arg += 5; if (starts_with( arg, -1, "//", 2 )) arg += 2; if (arg != cfg->val) warn( "%s:%d: Notice: URL notation is deprecated; use a plain host name and possibly 'SSLType IMAPS' instead\n", cfg->file, cfg->line ); server->sconf.host = nfstrdup( arg ); } else if (!strcasecmp( "User", cfg->cmd )) server->user = nfstrdup( cfg->val ); else if (!strcasecmp( "UserCmd", cfg->cmd )) server->user_cmd = nfstrdup( cfg->val ); else if (!strcasecmp( "Pass", cfg->cmd )) server->pass = nfstrdup( cfg->val ); else if (!strcasecmp( "PassCmd", cfg->cmd )) server->pass_cmd = nfstrdup( cfg->val ); #ifdef HAVE_MACOS_KEYCHAIN else if (!strcasecmp( "UseKeychain", cfg->cmd )) server->use_keychain = parse_bool( cfg ); #endif else if (!strcasecmp( "Port", cfg->cmd )) { int port = parse_int( cfg ); if ((unsigned)port > 0xffff) { error( "%s:%d: Invalid port number\n", cfg->file, cfg->line ); cfg->err = 1; } else { server->sconf.port = (ushort)port; } } else if (!strcasecmp( "Timeout", cfg->cmd )) server->sconf.timeout = parse_int( cfg ); else if (!strcasecmp( "PipelineDepth", cfg->cmd )) { if ((server->max_in_progress = parse_int( cfg )) < 1) { error( "%s:%d: PipelineDepth must be at least 1\n", cfg->file, cfg->line ); cfg->err = 1; } } else if (!strcasecmp( "DisableExtension", cfg->cmd ) || !strcasecmp( "DisableExtensions", cfg->cmd )) { arg = cfg->val; do { for (u = 0; u < as(cap_list); u++) { if (!strcasecmp( cap_list[u], arg )) { server->cap_mask |= 1 << u; goto gotcap; } } error( "%s:%d: Unrecognized IMAP extension '%s'\n", cfg->file, cfg->line, arg ); cfg->err = 1; gotcap: ; } while ((arg = get_arg( cfg, ARG_OPTIONAL, NULL ))); } #ifdef HAVE_LIBSSL else if (!strcasecmp( "CertificateFile", cfg->cmd )) { server->sconf.cert_file = expand_strdup( cfg->val ); if (access( server->sconf.cert_file, R_OK )) { sys_error( "%s:%d: CertificateFile '%s'", cfg->file, cfg->line, server->sconf.cert_file ); cfg->err = 1; } } else if (!strcasecmp( "SystemCertificates", cfg->cmd )) { server->sconf.system_certs = parse_bool( cfg ); } else if (!strcasecmp( "ClientCertificate", cfg->cmd )) { server->sconf.client_certfile = expand_strdup( cfg->val ); if (access( server->sconf.client_certfile, R_OK )) { sys_error( "%s:%d: ClientCertificate '%s'", cfg->file, cfg->line, server->sconf.client_certfile ); cfg->err = 1; } } else if (!strcasecmp( "ClientKey", cfg->cmd )) { server->sconf.client_keyfile = expand_strdup( cfg->val ); if (access( server->sconf.client_keyfile, R_OK )) { sys_error( "%s:%d: ClientKey '%s'", cfg->file, cfg->line, server->sconf.client_keyfile ); cfg->err = 1; } } else if (!strcasecmp( "CipherString", cfg->cmd )) { server->sconf.cipher_string = nfstrdup( cfg->val ); } else if (!strcasecmp( "SSLType", cfg->cmd )) { if (!strcasecmp( "None", cfg->val )) { server->ssl_type = SSL_None; } else if (!strcasecmp( "STARTTLS", cfg->val )) { server->ssl_type = SSL_STARTTLS; } else if (!strcasecmp( "IMAPS", cfg->val )) { server->ssl_type = SSL_IMAPS; } else { error( "%s:%d: Invalid SSL type\n", cfg->file, cfg->line ); cfg->err = 1; } } else if (!strcasecmp( "SSLVersion", cfg->cmd ) || !strcasecmp( "SSLVersions", cfg->cmd )) { server->sconf.ssl_versions = 0; arg = cfg->val; do { if (!strcasecmp( "SSLv2", arg )) { warn( "Warning: SSLVersion SSLv2 is no longer supported\n" ); } else if (!strcasecmp( "SSLv3", arg )) { warn( "Warning: SSLVersion SSLv3 is no longer supported\n" ); } else if (!strcasecmp( "TLSv1", arg )) { server->sconf.ssl_versions |= TLSv1; } else if (!strcasecmp( "TLSv1.1", arg )) { server->sconf.ssl_versions |= TLSv1_1; } else if (!strcasecmp( "TLSv1.2", arg )) { server->sconf.ssl_versions |= TLSv1_2; } else if (!strcasecmp( "TLSv1.3", arg )) { server->sconf.ssl_versions |= TLSv1_3; } else { error( "%s:%d: Unrecognized SSL version\n", cfg->file, cfg->line ); cfg->err = 1; } } while ((arg = get_arg( cfg, ARG_OPTIONAL, NULL ))); } else if (!strcasecmp( "RequireSSL", cfg->cmd )) require_ssl = parse_bool( cfg ); else if (!strcasecmp( "UseIMAPS", cfg->cmd )) use_imaps = parse_bool( cfg ); else if (!strcasecmp( "UseSSLv2", cfg->cmd )) warn( "Warning: UseSSLv2 is no longer supported\n" ); else if (!strcasecmp( "UseSSLv3", cfg->cmd )) warn( "Warning: UseSSLv3 is no longer supported\n" ); else if (!strcasecmp( "UseTLSv1", cfg->cmd )) use_tlsv1 = parse_bool( cfg ); else if (!strcasecmp( "UseTLSv1.1", cfg->cmd )) use_tlsv11 = parse_bool( cfg ); else if (!strcasecmp( "UseTLSv1.2", cfg->cmd )) use_tlsv12 = parse_bool( cfg ); else if (!strcasecmp( "UseTLSv1.3", cfg->cmd )) use_tlsv13 = parse_bool( cfg ); #endif else if (!strcasecmp( "AuthMech", cfg->cmd ) || !strcasecmp( "AuthMechs", cfg->cmd )) { arg = cfg->val; do add_string_list( &server->auth_mechs, arg ); while ((arg = get_arg( cfg, ARG_OPTIONAL, NULL ))); } else if (!strcasecmp( "RequireCRAM", cfg->cmd )) require_cram = parse_bool( cfg ); else if (!strcasecmp( "Tunnel", cfg->cmd )) server->sconf.tunnel = nfstrdup( cfg->val ); else if (store) { if (!strcasecmp( "Account", cfg->cmd )) { for (srv = servers; srv; srv = srv->next) if (srv->name && !strcmp( srv->name, cfg->val )) goto gotsrv; error( "%s:%d: unknown IMAP account '%s'\n", cfg->file, cfg->line, cfg->val ); cfg->err = 1; continue; gotsrv: store->server = srv; } else if (!strcasecmp( "UseNamespace", cfg->cmd )) store->use_namespace = parse_bool( cfg ); else if (!strcasecmp( "SubscribedOnly", cfg->cmd )) store->use_lsub = parse_bool( cfg ); else if (!strcasecmp( "Path", cfg->cmd )) store->path = nfstrdup( cfg->val ); else if (!strcasecmp( "PathDelimiter", cfg->cmd )) { if (strlen( cfg->val ) != 1) { error( "%s:%d: Path delimiter must be exactly one character long\n", cfg->file, cfg->line ); cfg->err = 1; continue; } store->delimiter = cfg->val[0]; } else parse_generic_store( &store->gen, cfg, "IMAPStore" ); continue; } else { error( "%s:%d: keyword '%s' is not recognized in IMAPAccount sections\n", cfg->file, cfg->line, cfg->cmd ); cfg->err = 1; continue; } acc_opt = 1; } if (!store || !store->server) { if (!server->sconf.tunnel && !server->sconf.host) { error( "%s '%s' has neither Tunnel nor Host\n", type, name ); cfg->err = 1; return 1; } if (server->user && server->user_cmd) { error( "%s '%s' has both User and UserCmd\n", type, name ); cfg->err = 1; return 1; } if (server->pass && server->pass_cmd) { error( "%s '%s' has both Pass and PassCmd\n", type, name ); cfg->err = 1; return 1; } #ifdef HAVE_MACOS_KEYCHAIN if (server->use_keychain && (server->pass || server->pass_cmd)) { error( "%s '%s' has UseKeychain enabled despite specifying Pass/PassCmd\n", type, name ); cfg->err = 1; return 1; } #endif #ifdef HAVE_LIBSSL if ((use_tlsv1 & use_tlsv11 & use_tlsv12 & use_tlsv13) != -1 || use_imaps >= 0 || require_ssl >= 0) { if (server->ssl_type >= 0 || server->sconf.ssl_versions >= 0) { error( "%s '%s': The deprecated UseSSL*, UseTLS*, UseIMAPS, and RequireSSL options are mutually exclusive with SSLType and SSLVersions.\n", type, name ); cfg->err = 1; return 1; } warn( "Notice: %s '%s': UseSSL*, UseTLS*, UseIMAPS, and RequireSSL are deprecated. Use SSLType and SSLVersions instead.\n", type, name ); server->sconf.ssl_versions = (use_tlsv1 == 0 ? 0 : TLSv1) | (use_tlsv11 != 1 ? 0 : TLSv1_1) | (use_tlsv12 != 1 ? 0 : TLSv1_2) | (use_tlsv13 != 1 ? 0 : TLSv1_3); if (use_imaps == 1) { server->ssl_type = SSL_IMAPS; } else if (require_ssl) { server->ssl_type = SSL_STARTTLS; } else if (!server->sconf.ssl_versions) { server->ssl_type = SSL_None; } else { warn( "Notice: %s '%s': 'RequireSSL no' is being ignored\n", type, name ); server->ssl_type = SSL_STARTTLS; } if (server->ssl_type != SSL_None && !server->sconf.ssl_versions) { error( "%s '%s' requires SSL but no SSL versions enabled\n", type, name ); cfg->err = 1; return 1; } } else { if (server->sconf.ssl_versions < 0) server->sconf.ssl_versions = TLSv1 | TLSv1_1 | TLSv1_2 | TLSv1_3; if (server->ssl_type < 0) server->ssl_type = server->sconf.tunnel ? SSL_None : SSL_STARTTLS; } #endif if (require_cram >= 0) { if (server->auth_mechs) { error( "%s '%s': The deprecated RequireCRAM option is mutually exclusive with AuthMech.\n", type, name ); cfg->err = 1; return 1; } warn( "Notice: %s '%s': RequireCRAM is deprecated. Use AuthMech instead.\n", type, name ); if (require_cram) add_string_list(&server->auth_mechs, "CRAM-MD5"); } if (!server->auth_mechs) add_string_list( &server->auth_mechs, "*" ); if (!server->sconf.port) server->sconf.port = #ifdef HAVE_LIBSSL server->ssl_type == SSL_IMAPS ? 993 : #endif 143; } if (store) { if (!store->server) { store->server = nfmalloc( sizeof(sserver) ); memcpy( store->server, &sserver, sizeof(sserver) ); store->server->name = store->name; } else if (acc_opt) { error( "%s '%s' has both Account and account-specific options\n", type, name ); cfg->err = 1; } } return 1; } static uint imap_get_caps( store_t *gctx ATTR_UNUSED ) { return DRV_CRLF | DRV_VERBOSE | DRV_ASYNC; } struct driver imap_driver = { imap_get_caps, imap_parse_store, imap_cleanup, imap_alloc_store, imap_set_bad_callback, imap_connect_store, imap_free_store, imap_cancel_store, imap_list_store, imap_select_box, imap_get_box_path, imap_create_box, imap_open_box, imap_get_uidnext, imap_get_supported_flags, imap_confirm_box_empty, imap_delete_box, imap_finish_delete_box, imap_prepare_load_box, imap_load_box, imap_fetch_msg, imap_store_msg, imap_find_new_msgs, imap_set_msg_flags, imap_trash_msg, imap_close_box, imap_cancel_cmds, imap_commit_cmds, imap_get_memory_usage, imap_get_fail_state, }; isync-1.4.4/src/mdconvert.c0000644000175000001440000001671714006611550012530 00000000000000/* * mdconvert - Maildir UID scheme converter * Copyright (C) 2004 Oswald Buddenhagen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #define EXE "mdconvert" #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4) # define ATTR_NORETURN __attribute__((noreturn)) # define ATTR_PRINTFLIKE(fmt,var) __attribute__((format(printf,fmt,var))) #else # define ATTR_NORETURN # define ATTR_PRINTFLIKE(fmt,var) #endif static void ATTR_NORETURN oob( void ) { fputs( "Fatal: buffer too small. Please report a bug.\n", stderr ); abort(); } static void ATTR_PRINTFLIKE(1, 2) sys_error( const char *msg, ... ) { va_list va; char buf[1024]; va_start( va, msg ); if ((unsigned)vsnprintf( buf, sizeof(buf), msg, va ) >= sizeof(buf)) oob(); va_end( va ); perror( buf ); } static int ATTR_PRINTFLIKE(3, 4) nfsnprintf( char *buf, int blen, const char *fmt, ... ) { int ret; va_list va; va_start( va, fmt ); if (blen <= 0 || (unsigned)(ret = vsnprintf( buf, blen, fmt, va )) >= (unsigned)blen) oob(); va_end( va ); return ret; } static const char *subdirs[] = { "cur", "new" }; static struct flock lck; static DBT key, value; static int convert( const char *box, int altmap ) { DB *db; DIR *d; struct dirent *e; const char *u, *ru; char *p, *s, *dpath, *spath, *dbpath; int i, n, ret, sfd, dfd, bl, ml, uv[2], uid; struct stat st; char buf[_POSIX_PATH_MAX], buf2[_POSIX_PATH_MAX]; char umpath[_POSIX_PATH_MAX], uvpath[_POSIX_PATH_MAX], tdpath[_POSIX_PATH_MAX]; if (stat( box, &st ) || !S_ISDIR(st.st_mode)) { fprintf( stderr, "'%s' is no Maildir mailbox.\n", box ); return 1; } nfsnprintf( umpath, sizeof(umpath), "%s/.isyncuidmap.db", box ); nfsnprintf( uvpath, sizeof(uvpath), "%s/.uidvalidity", box ); if (altmap) dpath = umpath, spath = uvpath, dbpath = tdpath; else spath = umpath, dpath = uvpath, dbpath = umpath; nfsnprintf( tdpath, sizeof(tdpath), "%s.tmp", dpath ); if ((sfd = open( spath, O_RDWR )) < 0) { if (errno != ENOENT) sys_error( "Cannot open %s", spath ); return 1; } if (fcntl( sfd, F_SETLKW, &lck )) { sys_error( "Cannot lock %s", spath ); goto sbork; } if ((dfd = open( tdpath, O_RDWR|O_CREAT, 0600 )) < 0) { sys_error( "Cannot create %s", tdpath ); goto sbork; } if (db_create( &db, NULL, 0 )) { fputs( "Error: db_create() failed\n", stderr ); goto tbork; } if ((ret = (db->open)( db, NULL, dbpath, NULL, DB_HASH, altmap ? DB_CREATE|DB_TRUNCATE : 0, 0 ))) { db->err( db, ret, "Error: db->open(%s)", dbpath ); dbork: db->close( db, 0 ); tbork: unlink( tdpath ); close( dfd ); sbork: close( sfd ); return 1; } key.data = (void *)"UIDVALIDITY"; key.size = 11; if (altmap) { if ((n = read( sfd, buf, sizeof(buf) - 1 )) <= 0 || (buf[n] = 0, sscanf( buf, "%d\n%d", &uv[0], &uv[1] ) != 2)) { fprintf( stderr, "Error: cannot read UIDVALIDITY of '%s'.\n", box ); goto dbork; } value.data = uv; value.size = sizeof(uv); if ((ret = db->put( db, NULL, &key, &value, 0 ))) { db->err( db, ret, "Error: cannot write UIDVALIDITY for '%s'", box ); goto dbork; } } else { if ((ret = db->get( db, NULL, &key, &value, 0 ))) { db->err( db, ret, "Error: cannot read UIDVALIDITY of '%s'", box ); goto dbork; } n = sprintf( buf, "%d\n%d\n", ((int *)value.data)[0], ((int *)value.data)[1] ); if (write( dfd, buf, n ) != n) { fprintf( stderr, "Error: cannot write UIDVALIDITY for '%s'.\n", box ); goto dbork; } } again: for (i = 0; i < 2; i++) { bl = nfsnprintf( buf, sizeof(buf), "%s/%s/", box, subdirs[i] ); if (!(d = opendir( buf ))) { sys_error( "Cannot list %s", buf ); goto dbork; } while ((e = readdir( d ))) { if (*e->d_name == '.') continue; nfsnprintf( buf + bl, sizeof(buf) - bl, "%s", e->d_name ); memcpy( buf2, buf, bl ); p = strstr( e->d_name, ",U=" ); if (p) for (u = p, ru = p + 3; isdigit( (unsigned char)*ru ); ru++); else u = ru = strchr( e->d_name, ':' ); if (u) ml = u - e->d_name; else ru = "", ml = sizeof(buf); if (altmap) { if (!p) continue; key.data = e->d_name; key.size = (size_t)(strchr( e->d_name, ',' ) - e->d_name); uid = atoi( p + 3 ); value.data = &uid; value.size = sizeof(uid); if ((ret = db->put( db, NULL, &key, &value, 0 ))) { db->err( db, ret, "Error: cannot write UID for '%s'", box ); goto ebork; } nfsnprintf( buf2 + bl, sizeof(buf2) - bl, "%.*s%s", ml, e->d_name, ru ); } else { s = strpbrk( e->d_name, ",:" ); key.data = e->d_name; key.size = s ? (size_t)(s - e->d_name) : strlen( e->d_name ); if ((ret = db->get( db, NULL, &key, &value, 0 ))) { if (ret != DB_NOTFOUND) { db->err( db, ret, "Error: cannot read UID for '%s'", box ); goto ebork; } continue; } uid = *(int *)value.data; nfsnprintf( buf2 + bl, sizeof(buf2) - bl, "%.*s,U=%d%s", ml, e->d_name, uid, ru ); } if (rename( buf, buf2 )) { if (errno == ENOENT) { closedir( d ); goto again; } sys_error( "Cannot rename %s to %s", buf, buf2 ); ebork: closedir( d ); goto dbork; } } closedir( d ); } db->close( db, 0 ); close( dfd ); if (rename( tdpath, dpath )) { sys_error( "Cannot rename %s to %s", tdpath, dpath ); close( sfd ); return 1; } if (unlink( spath )) sys_error( "Cannot remove %s", spath ); close( sfd ); return 0; } int main( int argc, char **argv ) { int oint, ret, altmap = 0; for (oint = 1; oint < argc; oint++) { if (!strcmp( argv[oint], "-h" ) || !strcmp( argv[oint], "--help" )) { puts( "Usage: " EXE " [-a] mailbox...\n" " -a, --alt convert to alternative (DB based) UID scheme\n" " -n, --native convert to native (file name based) UID scheme (default)\n" " -h, --help show this help message\n" " -v, --version display version" ); return 0; } else if (!strcmp( argv[oint], "-v" ) || !strcmp( argv[oint], "--version" )) { puts( EXE " " VERSION " - Maildir UID scheme converter" ); return 0; } else if (!strcmp( argv[oint], "-a" ) || !strcmp( argv[oint], "--alt" )) { altmap = 1; } else if (!strcmp( argv[oint], "-n" ) || !strcmp( argv[oint], "--native" )) { altmap = 0; } else if (!strcmp( argv[oint], "--" )) { oint++; break; } else if (argv[oint][0] == '-') { fprintf( stderr, "Unrecognized option '%s'. Try " EXE " -h\n", argv[oint] ); return 1; } else break; } if (oint == argc) { fprintf( stderr, "Mailbox specification missing. Try " EXE " -h\n" ); return 1; } #if SEEK_SET != 0 lck.l_whence = SEEK_SET; #endif #if F_WRLCK != 0 lck.l_type = F_WRLCK; #endif ret = 0; for (; oint < argc; oint++) ret |= convert( argv[oint], altmap ); return ret; } isync-1.4.4/src/mbsyncrc.sample0000644000175000001440000000334214006611550013374 00000000000000# Global configuration section # Values here are used as defaults for any following Channel section that # doesn't specify them. Expunge None Create Both MaildirStore local Path ~/Mail/ Trash Trash IMAPStore work Host work.host.com User tehuser Pass xxxxxxxx # Fetch password from gnome-keyring: #PassCmd "gnome-keyring-query get mail_pw" # Fetch password from .netrc: #PassCmd "sed -n -e 's,^machine work\\.host\\.com login tehuser password \\(.*\\),\\1,p' < $HOME/.netrc" # Fetch password from a gpg-encrypted file: #PassCmd "gpg --quiet --for-your-eyes-only --decrypt $HOME/imappassword.gpg" # Fetch password from pwmd (http://pwmd.sourceforge.net/): #PassCmd "echo -ne 'GET myIsp\\tpassword' | pwmc datafile" Channel work Far :work: Near :local:work Expunge Near Sync PullNew Push IMAPStore personal Host host.play.com Port 6789 RequireSSL no Channel personal Far :personal: Near :local:personal Expunge Both MaxMessages 150 MaxSize 200k IMAPStore remote Tunnel "ssh -q host.remote.com /usr/sbin/imapd" Channel remote Far :remote: Near :local:remote Group boxes Channels work personal remote IMAPStore st1 Host st1.domain.com RequireCRAM yes CertificateFile ~/.st1-certificate.crt IMAPStore st2 Host imap.another-domain.com Path non-standard/ RequireSSL no UseTLSv1 no Channel rst Far :st1:somebox Near :st2: IMAPAccount server Host imaps:foo.bar.com CertificateFile ~/.server-certificate.crt IMAPStore server Account server MapInbox inbox Trash ~/trash TrashRemoteNew yes MaildirStore mirror Path ~/Maildir/ SubFolders Verbatim Channel o2o Far :server: Near :mirror: Patterns % Group partial o2o:inbox,sent-mail,foobar # INBOX => server, INBOX.foo => server.foo, etc. Channel inbox Far :server:INBOX Near :mirror:server Patterns * isync-1.4.4/src/common.h0000644000175000001440000001656714152373720012035 00000000000000/* * mbsync - mailbox synchronizer * Copyright (C) 2000-2002 Michael R. Elkins * Copyright (C) 2002-2006,2010-2012 Oswald Buddenhagen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * As a special exception, mbsync may be linked with the OpenSSL library, * despite that library's more restrictive license. */ #ifndef COMMON_H #define COMMON_H #include #include #include #include #include typedef unsigned char uchar; typedef unsigned short ushort; typedef unsigned int uint; typedef unsigned long ulong; #define as(ar) (sizeof(ar)/sizeof(ar[0])) #define stringify__(x) #x #define stringify(x) stringify__(x) // From https://stackoverflow.com/a/62984543/3685191 #define deparen(x) esc_(ish_ x) #define esc_(...) esc__(__VA_ARGS__) #define esc__(...) van_ ## __VA_ARGS__ #define ish_(...) ish_ __VA_ARGS__ #define van_ish_ #define shifted_bit(in, from, to) \ ((int)(((uint)(in) / (from > to ? from / to : 1) * (to > from ? to / from : 1)) & to)) #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4) # define ATTR_UNUSED __attribute__((unused)) # define ATTR_NORETURN __attribute__((noreturn)) # define ATTR_PRINTFLIKE(fmt,var) __attribute__((format(printf,fmt,var))) #else # define ATTR_UNUSED # define ATTR_NORETURN # define ATTR_PRINTFLIKE(fmt,var) #endif #if defined(__clang__) # define DO_PRAGMA__(text) _Pragma(#text) # define DIAG_PUSH DO_PRAGMA__(clang diagnostic push) # define DIAG_POP DO_PRAGMA__(clang diagnostic pop) # define DIAG_DISABLE(text) DO_PRAGMA__(clang diagnostic ignored text) #elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 5) # define DO_PRAGMA__(text) _Pragma(#text) # define DIAG_PUSH DO_PRAGMA__(GCC diagnostic push) # define DIAG_POP DO_PRAGMA__(GCC diagnostic pop) # define DIAG_DISABLE(text) DO_PRAGMA__(GCC diagnostic ignored text) #else # define DIAG_PUSH # define DIAG_POP # define DIAG_DISABLE(text) #endif #if __GNUC__ >= 7 || defined(__clang__) # define FALLTHROUGH __attribute__((fallthrough)); #else # define FALLTHROUGH #endif #ifdef __GNUC__ # define INLINE __inline__ #else # define INLINE #endif #define EXE "mbsync" /* main.c */ #define DEBUG_CRASH 0x01 #define DEBUG_MAILDIR 0x02 #define DEBUG_NET 0x04 #define DEBUG_NET_ALL 0x08 #define DEBUG_SYNC 0x10 #define DEBUG_MAIN 0x20 #define DEBUG_DRV 0x40 #define DEBUG_DRV_ALL 0x80 #define DEBUG_ALL (0xFF & ~(DEBUG_NET_ALL | DEBUG_DRV_ALL)) #define QUIET 0x100 #define VERYQUIET 0x200 #define PROGRESS 0x400 #define VERBOSE 0x800 #define KEEPJOURNAL 0x1000 #define ZERODELAY 0x2000 #define FORCEASYNC 0x4000 extern int DFlags; extern int JLimit; extern int UseFSync; extern char FieldDelimiter; extern int Pid; extern char Hostname[256]; extern const char *Home; extern uint BufferLimit; extern int new_total[2], new_done[2]; extern int flags_total[2], flags_done[2]; extern int trash_total[2], trash_done[2]; void stats( void ); /* util.c */ void ATTR_PRINTFLIKE(2, 0) vdebug( int, const char *, va_list va ); void ATTR_PRINTFLIKE(2, 0) vdebugn( int, const char *, va_list va ); void ATTR_PRINTFLIKE(1, 2) info( const char *, ... ); void ATTR_PRINTFLIKE(1, 2) infon( const char *, ... ); void ATTR_PRINTFLIKE(1, 2) progress( const char *, ... ); void ATTR_PRINTFLIKE(1, 2) notice( const char *, ... ); void ATTR_PRINTFLIKE(1, 2) warn( const char *, ... ); void ATTR_PRINTFLIKE(1, 2) error( const char *, ... ); void ATTR_PRINTFLIKE(1, 0) vsys_error( const char *, va_list va ); void ATTR_PRINTFLIKE(1, 2) sys_error( const char *, ... ); void flushn( void ); typedef struct string_list { struct string_list *next; char string[1]; } string_list_t; void add_string_list_n( string_list_t **list, const char *str, uint len ); void add_string_list( string_list_t **list, const char *str ); void free_string_list( string_list_t *list ); #ifndef HAVE_MEMRCHR void *memrchr( const void *s, int c, size_t n ); #endif #ifndef HAVE_STRNLEN size_t strnlen( const char *str, size_t maxlen ); #endif int starts_with( const char *str, int strl, const char *cmp, uint cmpl ); int starts_with_upper( const char *str, int strl, const char *cmp, uint cmpl ); int equals( const char *str, int strl, const char *cmp, uint cmpl ); #ifndef HAVE_TIMEGM time_t timegm( struct tm *tm ); #endif void *nfmalloc( size_t sz ); void *nfcalloc( size_t sz ); void *nfrealloc( void *mem, size_t sz ); char *nfstrndup( const char *str, size_t nchars ); char *nfstrdup( const char *str ); int ATTR_PRINTFLIKE(2, 0) nfvasprintf( char **str, const char *fmt, va_list va ); int ATTR_PRINTFLIKE(2, 3) nfasprintf( char **str, const char *fmt, ... ); int ATTR_PRINTFLIKE(3, 4) nfsnprintf( char *buf, int blen, const char *fmt, ... ); void ATTR_NORETURN oob( void ); void ATTR_NORETURN oom( void ); char *expand_strdup( const char *s ); int map_name( const char *arg, char **result, uint reserve, const char *in, const char *out ); #define DEFINE_ARRAY_TYPE(T) \ typedef struct { \ T *data; \ uint size; \ } T##_array_t; \ typedef union { \ T##_array_t array; \ struct { \ T *data; \ uint size; \ uint alloc; \ }; \ } T##_array_alloc_t; \ static INLINE T *T##_array_append( T##_array_alloc_t *arr ) \ { \ if (arr->size == arr->alloc) { \ arr->alloc = arr->alloc * 2 + 100; \ arr->data = nfrealloc( arr->data, arr->alloc * sizeof(T) ); \ } \ return &arr->data[arr->size++]; \ } #define ARRAY_INIT(arr) \ do { (arr)->data = NULL; (arr)->size = (arr)->alloc = 0; } while (0) #define ARRAY_SQUEEZE(arr) \ do { \ (arr)->data = nfrealloc( (arr)->data, (arr)->size * sizeof((arr)->data[0]) ); \ } while (0) DEFINE_ARRAY_TYPE(uint) void sort_uint_array( uint_array_t array ); int find_uint_array( const uint_array_t array, uint value ); void arc4_init( void ); uchar arc4_getbyte( void ); uint bucketsForSize( uint size ); typedef struct list_head { struct list_head *next, *prev; } list_head_t; typedef struct notifier { struct notifier *next; void (*cb)( int what, void *aux ); void *aux; #ifdef HAVE_POLL_H uint index; #else int fd; short events; #endif } notifier_t; #ifdef HAVE_POLL_H # include #else # define POLLIN 1 # define POLLOUT 4 # define POLLERR 8 #endif void init_notifier( notifier_t *sn, int fd, void (*cb)( int, void * ), void *aux ); void conf_notifier( notifier_t *sn, short and_events, short or_events ); short notifier_config( notifier_t *sn ); void wipe_notifier( notifier_t *sn ); typedef struct { list_head_t links; void (*cb)( void *aux ); void *aux; time_t timeout; } wakeup_t; void init_wakeup( wakeup_t *tmr, void (*cb)( void * ), void *aux ); void conf_wakeup( wakeup_t *tmr, int timeout ); void wipe_wakeup( wakeup_t *tmr ); static INLINE int ATTR_UNUSED pending_wakeup( wakeup_t *tmr ) { return tmr->links.next != NULL; } void main_loop( void ); #endif isync-1.4.4/src/config.h0000644000175000001440000000274714006611550011777 00000000000000/* * mbsync - mailbox synchronizer * Copyright (C) 2000-2002 Michael R. Elkins * Copyright (C) 2002-2006,2010-2012 Oswald Buddenhagen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * As a special exception, mbsync may be linked with the OpenSSL library, * despite that library's more restrictive license. */ #ifndef CONFIG_H #define CONFIG_H #include "common.h" typedef struct { const char *file; FILE *fp; char *buf; int bufl; int line; int err; int ms_warn; char *cmd, *val, *rest; } conffile_t; #define ARG_OPTIONAL 0 #define ARG_REQUIRED 1 char *get_arg( conffile_t *cfile, int required, int *comment ); char parse_bool( conffile_t *cfile ); int parse_int( conffile_t *cfile ); uint parse_size( conffile_t *cfile ); int getcline( conffile_t *cfile ); int merge_ops( int cops, int ops[] ); int load_config( const char *filename ); #endif isync-1.4.4/src/mbsync.10000644000175000001440000010103414006611550011723 00000000000000.\" mbsync - mailbox synchronizer .\" Copyright (C) 2000-2002 Michael R. Elkins .\" Copyright (C) 2002-2004,2011-2015 Oswald Buddenhagen .\" Copyright (C) 2004 Theodore Y. Ts'o .\" .\" This program is free software; you can redistribute it and/or modify .\" it under the terms of the GNU General Public License as published by .\" the Free Software Foundation; either version 2 of the License, or .\" (at your option) any later version. .\" .\" This program is distributed in the hope that it will be useful, .\" but WITHOUT ANY WARRANTY; without even the implied warranty of .\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the .\" GNU General Public License for more details. .\" .\" You should have received a copy of the GNU General Public License .\" along with this program. If not, see . .\" .\" As a special exception, mbsync may be linked with the OpenSSL library, .\" despite that library's more restrictive license. . .TH mbsync 1 "2015 Mar 22" . .SH NAME mbsync - synchronize IMAP4 and Maildir mailboxes . .SH SYNOPSIS \fBmbsync\fR [\fIoptions\fR ...] {{\fIchannel\fR[\fB:\fIbox\fR[{\fB,\fR|\fB\\n\fR}...]]|\fIgroup\fR} ...|\fB-a\fR} . .SH DESCRIPTION \fBmbsync\fR is a command line application which synchronizes mailboxes; currently Maildir and IMAP4 mailboxes are supported. New messages, message deletions and flag changes can be propagated both ways; the operation set can be selected in a fine-grained manner. .br Synchronization is based on unique message identifiers (UIDs), so no identification conflicts can occur (unlike with some other mail synchronizers). OTOH, \fBmbsync\fR is susceptible to UID validity changes (but will recover just fine if the change is unfounded). Synchronization state is kept in one local text file per mailbox pair; these files are protected against concurrent \fBmbsync\fR processes. Mailboxes can be safely modified while \fBmbsync\fR operates (see \fBINHERENT PROBLEMS\fR below for a minor exception). Multiple replicas of each mailbox can be maintained. . .SH OPTIONS .TP \fB-c\fR, \fB--config\fR \fIfile\fR Read configuration from \fIfile\fR. By default, the configuration is read from ~/.mbsyncrc. .TP \fB-a\fR, \fB--all\fR Select all configured channels. Any channel/group specifications on the command line are ignored. .TP \fB-l\fR, \fB--list\fR Don't synchronize anything, but list all mailboxes in the selected channels and exit. .TP \fB-C\fR[\fBf\fR][\fBn\fR], \fB--create\fR[\fB-far\fR|\fB-near\fR] Override any \fBCreate\fR options from the config file. See below. .TP \fB-R\fR[\fBf\fR][\fBn\fR], \fB--remove\fR[\fB-far\fR|\fB-near\fR] Override any \fBRemove\fR options from the config file. See below. .TP \fB-X\fR[\fBf\fR][\fBn\fR], \fB--expunge\fR[\fB-far\fR|\fB-near\fR] Override any \fBExpunge\fR options from the config file. See below. .TP {\fB-n\fR|\fB-N\fR|\fB-d\fR|\fB-f\fR|\fB-0\fR|\fB-F\fR},\ {\fB--new\fR|\fB--renew\fR|\fB--delete\fR|\fB--flags\fR|\fB--noop\fR|\fB--full\fR} .TP \r{\fB-L\fR|\fB-H\fR}[\fBn\fR][\fBN\fR][\fBd\fR][\fBf\fR],\ {\fB--pull\fR|\fB--push\fR}[\fB-new\fR|\fB-renew\fR|\fB-delete\fR|\fB-flags\fR] Override any \fBSync\fR options from the config file. See below. .TP \fB-h\fR, \fB--help\fR Display a summary of command line options. .TP \fB-v\fR, \fB--version\fR Display version information. .TP \fB-V\fR, \fB--verbose\fR Enable \fIverbose\fR mode, which displays what is currently happening. .TP \fB-D\fR[\fBC\fR][\fBd\fR|\fBD\fR][\fBm\fR][\fBM\fR][\fBn\fR|\fBN\fR][\fBs\fR]\fR]\fR,\ \fB--debug\fR[\fB-crash\fR|\fB-driver\fR|\fB-driver-all\fR|\fB-maildir\fR|\fB-main\fR|\fB-net\fR|\fB-net-all\fR|\fB-sync\fR] Enable debugging categories: .in +4 \fBC\fR, \fBcrash\fR - use built-in crash handler .br \fBd\fR, \fBdriver\fR - print driver calls (metadata only) .br \fBD\fR, \fBdriver-all\fR - print driver calls (including messages) .br \fBm\fR, \fBmaildir\fR - print maildir debug info .br \fBM\fR, \fBmain\fR - print main debug info .br \fBn\fR, \fBnet\fR - print network traffic (protocol only) .br \fBN\fR, \fBnet-all\fR - print network traffic (including payloads) .br \fBs\fR, \fBsync\fR - print synchronization debug info .in -4 All categories except \fBcrash\fR implictly enable \fIverbose\fR mode. Without category specification, all categories except net-all are enabled. .TP \fB-q\fR, \fB--quiet\fR Suppress progress counters (this is implicit if stdout is no TTY, or any debugging categories are enabled) and notices. If specified twice, suppress warning messages as well. . .SH CONFIGURATION The configuration file is mandatory; \fBmbsync\fR will not run without it. Lines starting with a hash mark (\fB#\fR) are comments and are ignored entirely. Configuration items are keywords followed by one or more arguments; arguments containing spaces must be enclosed in double quotes (\fB"\fR), and literal double quotes and backslashes (\fB\\\fR) must be backslash-escaped. All keywords (including those used as arguments) are case-insensitive. Bash-like home directory expansion using the tilde (\fB~\fR) is supported in all options which represent local paths. There are a few global options, the others apply to particular sections. Sections begin with a section-starting keyword and are terminated by an empty line or end of file. Every section defines an object with an identifier unique within that object class. .P There are two basic object classes: Stores and Channels. A Store defines a collection of mailboxes; basically a folder, either local or remote. A Channel connects two Stores, describing the way the two are synchronized. .br There are two auxiliary object classes: Accounts and Groups. An Account describes the connection part of network Stores, so server configurations can be shared between multiple Stores. A Group aggregates multiple Channels to save typing on the command line. .P File system locations (in particular, \fBPath\fR and \fBInbox\fR) use the Store's internal path separators, which may be slashes, periods, etc., or even combinations thereof. .br Mailbox names, OTOH, always use canonical path separators, which are Unix-like forward slashes. . .SS All Stores These options can be used in all supported Store types. .br In this context, the term "remote" describes the second Store within a Channel, and not necessarily a remote server. .br The special mailbox \fBINBOX\fR exists in every Store; its physical location in the file system is Store type specific. . .TP \fBPath\fR \fIpath\fR The location of the Store in the (server's) file system. If this is no absolute path, the reference point is Store type specific. This string is prepended to the mailbox names addressed in this Store, but is not considered part of them; this is important for \fBPatterns\fR and \fBCreate\fR in the Channels section. Note that you \fBmust\fR append a slash if you want to specify an entire directory. (Default: none) . .TP \fBMaxSize\fR \fIsize\fR[\fBk\fR|\fBm\fR][\fBb\fR] Messages larger than \fIsize\fR will have only a small placeholder message propagated into this Store. To propagate the full message, it must be flagged in either Store; that can be done retroactively, in which case the \fBReNew\fR operation needs to be executed instead of \fBNew\fR. This is useful for avoiding downloading messages with large attachments unless they are actually needed. Caveat: Setting a size limit on a Store you never read directly (which is typically the case for servers) is not recommended, as you may never notice that affected messages were not propagated to it. .br \fBK\fR and \fBM\fR can be appended to the size to specify KiBytes resp. MeBytes instead of bytes. \fBB\fR is accepted but superfluous. If \fIsize\fR is 0, the maximum message size is \fBunlimited\fR. (Default: \fI0\fR) . .TP \fBMapInbox\fR \fImailbox\fR Create a virtual mailbox (relative to \fBPath\fR) which aliases the \fBINBOX\fR. Makes sense in conjunction with \fBPatterns\fR in the Channels section, though with a Maildir near side, you probably want to place \fBInbox\fR under \fBPath\fR instead. This virtual mailbox does not support subfolders. . .TP \fBFlatten\fR \fIdelim\fR Flatten the hierarchy within this Store by substituting the canonical hierarchy delimiter \fB/\fR with \fIdelim\fR. This can be useful when the MUA used to access the Store provides suboptimal handling of hierarchical mailboxes, as is the case with \fBMutt\fR. A common choice for the delimiter is \fB.\fR. .br Note that flattened sub-folders of the \fBINBOX\fR always end up under \fBPath\fR, including the "INBOX\fIdelim\fR" prefix. . .TP \fBTrash\fR \fImailbox\fR Specifies a mailbox (relative to \fBPath\fR) to copy deleted messages to prior to expunging. See \fBRECOMMENDATIONS\fR and \fBINHERENT PROBLEMS\fR below. (Default: none) . .TP \fBTrashNewOnly\fR \fByes\fR|\fBno\fR When trashing, copy only not yet propagated messages. This makes sense if the remote Store has a \fBTrash\fR as well (with \fBTrashNewOnly\fR \fBno\fR). (Default: \fBno\fR) . .TP \fBTrashRemoteNew\fR \fByes\fR|\fBno\fR When expunging the remote Store, copy not yet propagated messages to this Store's \fBTrash\fR. When using this, the remote Store does not need an own \fBTrash\fR at all, yet all messages are archived. (Default: \fBno\fR) . .SS Maildir Stores The reference point for relative \fBPath\fRs is the current working directory. .P As \fBmbsync\fR needs UIDs, but no standardized UID storage scheme exists for Maildir, \fBmbsync\fR supports two schemes, each with its pros and cons. .br The \fBnative\fR scheme is stolen from the latest Maildir patches to \fBc-client\fR and is therefore compatible with \fBpine\fR. The UID validity is stored in a file named .uidvalidity; the UIDs are encoded in the file names of the messages. .br The \fBalternative\fR scheme is based on the UID mapping used by \fBisync\fR versions 0.8 and 0.9.x. The invariant parts of the file names of the messages are used as keys into a Berkeley database named .isyncuidmap.db, which holds the UID validity as well. .br The \fBnative\fR scheme is faster, more space efficient, endianness independent and "human readable", but will be disrupted if a message is copied from another mailbox without getting a new file name; this would result in duplicated UIDs sooner or later, which in turn results in a UID validity change, making synchronization fail. The \fBalternative\fR scheme would fail if a MUA changed a message's file name in a part \fBmbsync\fR considers invariant; this would be interpreted as a message deletion and a new message, resulting in unnecessary traffic. .br \fBMutt\fR is known to work fine with both schemes. .br Use \fBmdconvert\fR to convert mailboxes from one scheme to the other. . .TP \fBMaildirStore\fR \fIname\fR Define the Maildir Store \fIname\fR, opening a section for its parameters. . .TP \fBAltMap\fR \fByes\fR|\fBno\fR Use the \fBalternative\fR UID storage scheme for mailboxes in this Store. This does not affect mailboxes that do already have a UID storage scheme; use \fBmdconvert\fR to change it. See \fBRECOMMENDATIONS\fR below. (Default: \fBno\fR) . .TP \fBInbox\fR \fIpath\fR The location of the \fBINBOX\fR. This is \fInot\fR relative to \fBPath\fR, but it is allowed to place the \fBINBOX\fR inside the \fBPath\fR. (Default: \fI~/Maildir\fR) . .TP \fBInfoDelimiter\fR \fIdelim\fR The character used to delimit the info field from a message's basename. The Maildir standard defines this to be the colon, but this is incompatible with DOS/Windows file systems. (Default: the value of \fBFieldDelimiter\fR) . .TP \fBSubFolders\fR \fBVerbatim\fR|\fBMaildir++\fR|\fBLegacy\fR The on-disk folder naming style used for hierarchical mailboxes. This option has no effect when \fBFlatten\fR is used. .br Suppose mailboxes with the canonical paths \fBtop/sub/subsub\fR and \fBINBOX/sub/subsub\fR, the styles will yield the following on-disk paths: .br \fBVerbatim\fR - \fIPath\fB/top/sub/subsub\fR and \fIInbox\fB/sub/subsub\fR (this is the style you probably want to use) .br \fBMaildir++\fR - \fIInbox\fB/.top.sub.subsub\fR and \fIInbox\fB/..sub.subsub\fR (this style is compatible with Courier and Dovecot - but note that the mailbox metadata format is \fInot\fR compatible). Note that attempts to set \fBPath\fR are rejected in this mode. .br \fBLegacy\fR - \fIPath\fB/top/.sub/.subsub\fR and \fIInbox\fB/.sub/.subsub\fR (this is \fBmbsync\fR's historical style) .br (Default: unset; will error out when sub-folders are encountered) . .SS IMAP4 Accounts .TP \fBIMAPAccount\fR \fIname\fR Define the IMAP4 Account \fIname\fR, opening a section for its parameters. . .TP \fBHost\fR \fIhost\fR Specify the DNS name or IP address of the IMAP server. .br If \fBTunnel\fR is used, this setting is needed only if \fBSSLType\fR is not \fBNone\fR and \fBCertificateFile\fR is not used, in which case the host name is used for certificate subject verification. . .TP \fBPort\fR \fIport\fR Specify the TCP port number of the IMAP server. (Default: 143 for IMAP, 993 for IMAPS) .br If \fBTunnel\fR is used, this setting is ignored. . .TP \fBTimeout\fR \fItimeout\fR Specify the connect and data timeout for the IMAP server in seconds. Zero means unlimited. (Default: \fI20\fR) . .TP \fBUser\fR \fIusername\fR Specify the login name on the IMAP server. . .TP \fBUserCmd\fR [\fB+\fR]\fIcommand\fR Specify a shell command to obtain a user rather than specifying a user directly. This allows you to script retrieving user names. .br The command must produce exactly one line on stdout; the trailing newline is optional. Prepend \fB+\fR to the command to indicate that it produces TTY output (e.g., a prompt); failure to do so will merely produce messier output. Remember to backslash-escape double quotes and backslashes embedded into the command. . .TP \fBPass\fR \fIpassword\fR Specify the password for \fIusername\fR on the IMAP server. Note that this option is \fInot\fR required. If neither a password nor a password command is specified in the configuration file, \fBmbsync\fR will prompt you for a password. . .TP \fBPassCmd\fR [\fB+\fR]\fIcommand\fR Specify a shell command to obtain a password rather than specifying a password directly. This allows you to use password files and agents. .br See \fBUserCmd\fR above for details. . .TP \fBUseKeychain\fR \fByes\fR|\fBno\fR Whether to use the macOS Keychain to obtain the password. (Default: \fBno\fR) .IP The neccessary keychain item can be created this way: .RS .IP .nh .B security add-internet-password \-r imap \-s .I Host .B \-a .I User .B \-w .I password [ .B \-T .I /path/to/mbsync ] .hy .RE . .TP \fBTunnel\fR \fIcommand\fR Specify a command to run to establish a connection rather than opening a TCP socket. This allows you to run an IMAP session over an SSH tunnel, for example. . .TP \fBAuthMechs\fR \fItype\fR ... The list of acceptable authentication mechanisms. In addition to the mechanisms listed in the SASL registry (link below), the legacy IMAP \fBLOGIN\fR mechanism is known. The wildcard \fB*\fR represents all mechanisms that are deemed secure enough for the current \fBSSLType\fR setting. The actually used mechanism is the most secure choice from the intersection of this list, the list supplied by the server, and the installed SASL modules. (Default: \fB*\fR) . .TP \fBSSLType\fR {\fBNone\fR|\fBSTARTTLS\fR|\fBIMAPS\fR} Select the connection security/encryption method: .br \fBNone\fR - no security. This is the default when \fBTunnel\fR is set, as tunnels are usually secure. .br \fBSTARTTLS\fR - security is established via the STARTTLS extension after connecting the regular IMAP port 143. Most servers support this, so it is the default (unless a tunnel is used). .br \fBIMAPS\fR - security is established by starting SSL/TLS negotiation right after connecting the secure IMAP port 993. . .TP \fBSSLVersions\fR [\fBSSLv3\fR] [\fBTLSv1\fR] [\fBTLSv1.1\fR] [\fBTLSv1.2\fR] [\fBTLSv1.3\fR] Select the acceptable SSL/TLS versions. Use old versions only when the server has problems with newer ones. (Default: [\fBTLSv1\fR] [\fBTLSv1.1\fR] [\fBTLSv1.2\fR] [\fBTLSv1.3\fR]). . .TP \fBSystemCertificates\fR \fByes\fR|\fBno\fR Whether the system's default CA (certificate authority) certificate store should be used to verify certificate trust chains. Disable this if you want to trust only hand-picked certificates. (Default: \fByes\fR) . .TP \fBCertificateFile\fR \fIpath\fR File containing additional X.509 certificates used to verify server identities. It may contain two types of certificates: .RS .IP Host These certificates are matched only against the received server certificate itself. They are always trusted, regardless of validity. A typical use case would be forcing acceptance of an expired certificate. .br These certificates may be obtained using the \fBmbsync-get-cert\fR tool; make sure to verify their fingerprints before trusting them, or transfer them securely from the server's network (if it can be trusted beyond the server itself). .IP CA These certificates are used as trust anchors when building the certificate chain for the received server certificate. They are used to supplant or supersede the system's trust store, depending on the \fBSystemCertificates\fR setting; it is not necessary and not recommended to specify the system's trust store itself here. The trust chains are fully validated. .RE . .TP \fBClientCertificate\fR \fIpath\fR File containing a client certificate to send to the server. \fBClientKey\fR should also be specified. .br Note that client certificate verification is usually not required, so it is unlikely that you need this option. . .TP \fBClientKey\fR \fIpath\fR File containing the private key corresponding to \fBClientCertificate\fR. . .TP \fBCipherString\fR \fIstring\fR Specify OpenSSL cipher string for connections secured with TLS up to version 1.2 (but not 1.3 and above). The format is described in \fBciphers\fR\|(1). (Default: empty, which implies system wide policy). . .TP \fBPipelineDepth\fR \fIdepth\fR Maximum number of IMAP commands which can be simultaneously in flight. Setting this to \fI1\fR disables pipelining. This is mostly a debugging option, but may also be used to limit average bandwidth consumption (GMail may require this if you have a very fast connection), or to spare flaky servers like M$ Exchange. (Default: \fIunlimited\fR) . .TP \fBDisableExtension\fR[\fBs\fR] \fIextension\fR ... Disable the use of specific IMAP extensions. This can be used to work around bugs in servers (and possibly \fBmbsync\fR itself). (Default: empty) . .SS IMAP Stores The reference point for relative \fBPath\fRs is whatever the server likes it to be; probably the user's $HOME or $HOME/Mail on that server. The location of \fBINBOX\fR is up to the server as well and is usually irrelevant. .TP \fBIMAPStore\fR \fIname\fR Define the IMAP4 Store \fIname\fR, opening a section for its parameters. . .TP \fBAccount\fR \fIaccount\fR Specify which IMAP4 Account to use. Instead of defining an Account and referencing it here, it is also possible to specify all the Account options directly in the Store's section - this makes sense if an Account is used for one Store only anyway. . .TP \fBUseNamespace\fR \fByes\fR|\fBno\fR Selects whether the server's first "personal" NAMESPACE should be prefixed to mailbox names. Disabling this makes sense for some broken IMAP servers. This option is meaningless if a \fBPath\fR was specified. (Default: \fByes\fR) . .TP \fBPathDelimiter\fR \fIdelim\fR Specify the server's hierarchy delimiter. (Default: taken from the server's first "personal" NAMESPACE) .br Do \fInot\fR abuse this to re-interpret the hierarchy. Use \fBFlatten\fR instead. . .TP \fBSubscribedOnly\fR \fByes\fR|\fBno\fR Selects whether to synchronize only mailboxes that are subscribed to on the IMAP server. In technical terms, if this option is set, \fBmbsync\fR will use the IMAP command LSUB instead of LIST to look for mailboxes in this Store. This option make sense only in conjunction with \fBPatterns\fR. (Default: \fBno\fR) . .SS Channels .TP \fBChannel\fR \fIname\fR Define the Channel \fIname\fR, opening a section for its parameters. . .TP {\fBFar\fR|\fBNear\fR} \fB:\fIstore\fB:\fR[\fImailbox\fR] Specify the far resp. near side Store to be connected by this Channel. If \fBPatterns\fR are specified, \fImailbox\fR is interpreted as a prefix which is not matched against the patterns, and which is not affected by mailbox list overrides. Otherwise, if \fImailbox\fR is omitted, \fBINBOX\fR is assumed. . .TP \fBPattern\fR[\fBs\fR] [\fB!\fR]\fIpattern\fR ... Instead of synchronizing only one mailbox pair, synchronize all mailboxes that match the \fIpattern\fR(s). The mailbox names are the same on the far and near side. Patterns are IMAP4 patterns, i.e., \fB*\fR matches anything and \fB%\fR matches anything up to the next hierarchy delimiter. Prepending \fB!\fR to a pattern makes it an exclusion. Multiple patterns can be specified (either by supplying multiple arguments or by using \fBPattern\fR multiple times); later matches take precedence. .br Note that \fBINBOX\fR is not matched by wildcards, unless it lives under \fBPath\fR. .br The mailbox list selected by \fBPatterns\fR can be overridden by a mailbox list in a channel reference (a \fBGroup\fR specification or the command line). .br Example: "\fBPatterns\fR\ \fI%\ !Trash\fR" . .TP \fBMaxSize\fR \fIsize\fR[\fBk\fR|\fBm\fR][\fBb\fR] Analogous to the homonymous option in the Stores section, but applies equally to Far and Near. Note that this actually modifies the Stores, so take care not to provide conflicting settings if you use the Stores in multiple Channels. . .TP \fBMaxMessages\fR \fIcount\fR Sets the maximum number of messages to keep in each near side mailbox. This is useful for mailboxes where you keep a complete archive on the server, but want to mirror only the last messages (for instance, for mailing lists). The messages that were the first to arrive in the mailbox (independently of the actual date of the message) will be deleted first. Messages that are flagged (marked as important) and (by default) unread messages will not be automatically deleted. If \fIcount\fR is 0, the maximum number of messages is \fBunlimited\fR (Default: \fI0\fR). . .TP \fBExpireUnread\fR \fByes\fR|\fBno\fR Selects whether unread messages should be affected by \fBMaxMessages\fR. Normally, unread messages are considered important and thus never expired. This ensures that you never miss new messages even after an extended absence. However, if your archive contains large amounts of unread messages by design, treating them as important would practically defeat \fBMaxMessages\fR. In this case you need to enable this option. (Default: \fBno\fR). . .TP \fBSync\fR {\fBNone\fR|[\fBPull\fR] [\fBPush\fR] [\fBNew\fR] [\fBReNew\fR] [\fBDelete\fR] [\fBFlags\fR]|\fBAll\fR} Select the synchronization operation(s) to perform: .br \fBPull\fR - propagate changes from far to near side. .br \fBPush\fR - propagate changes from near to far side. .br \fBNew\fR - propagate newly appeared messages. .br \fBReNew\fR - upgrade placeholders to full messages. Useful only with a configured \fBMaxSize\fR. .br \fBDelete\fR - propagate message deletions. This applies only to messages that are actually gone, i.e., were expunged. The affected messages in the remote Store are marked as deleted only, i.e., they won't be really deleted until that Store is expunged. .br \fBFlags\fR - propagate flag changes. Note that Deleted/Trashed is a flag as well; this is particularly interesting if you use \fBmutt\fR with the maildir_trash option. .br \fBAll\fR (\fB--full\fR on the command line) - all of the above. This is the global default. .br \fBNone\fR (\fB--noop\fR on the command line) - don't propagate anything. Useful if you want to expunge only. .IP \fBPull\fR and \fBPush\fR are direction flags, while \fBNew\fR, \fBReNew\fR, \fBDelete\fR and \fBFlags\fR are type flags. The two flag classes make up a two-dimensional matrix (a table). Its cells are the individual actions to perform. There are two styles of asserting the cells: .br In the first style, the flags select entire rows/colums in the matrix. Only the cells which are selected both horizontally and vertically are asserted. Specifying no flags from a class is like specifying all flags from this class. For example, "\fBSync\fR\ \fBPull\fR\ \fBNew\fR\ \fBFlags\fR" will propagate new messages and flag changes from the far side to the near side, "\fBSync\fR\ \fBNew\fR\ \fBDelete\fR" will propagate message arrivals and deletions both ways, and "\fBSync\fR\ \fBPush\fR" will propagate all changes from the near side to the far side. .br In the second style, direction flags are concatenated with type flags; every compound flag immediately asserts a cell in the matrix. In addition to at least one compound flag, the individual flags can be used as well, but as opposed to the first style, they immediately assert all cells in their respective row/column. For example, "\fBSync\fR\ \fBPullNew\fR\ \fBPullDelete\fR\ \fBPush\fR" will propagate message arrivals and deletions from the far side to the near side and any changes from the near side to the far side. Note that it is not allowed to assert a cell in two ways, e.g. "\fBSync\fR\ \fBPullNew\fR\ \fBPull\fR" and "\fBSync\fR\ \fBPullNew\fR\ \fBDelete\fR\ \fBPush\fR" induce error messages. . .TP \fBCreate\fR {\fBNone\fR|\fBFar\fR|\fBNear\fR|\fBBoth\fR} Automatically create missing mailboxes [on the far/near side]. Otherwise print an error message and skip that mailbox pair if a mailbox and the corresponding sync state does not exist. (Global default: \fBNone\fR) . .TP \fBRemove\fR {\fBNone\fR|\fBFar\fR|\fBNear\fR|\fBBoth\fR} Propagate mailbox deletions [to the far/near side]. Otherwise print an error message and skip that mailbox pair if a mailbox does not exist but the corresponding sync state does. .br For MailDir mailboxes it is sufficient to delete the cur/ subdirectory to mark them as deleted. This ensures compatibility with \fBSyncState *\fR. .br Note that for safety, non-empty mailboxes are never deleted. .br (Global default: \fBNone\fR) . .TP \fBExpunge\fR {\fBNone\fR|\fBFar\fR|\fBNear\fR|\fBBoth\fR} Permanently remove all messages [on the far/near side] marked for deletion. See \fBRECOMMENDATIONS\fR below. (Global default: \fBNone\fR) . .TP \fBCopyArrivalDate\fR {\fByes\fR|\fBno\fR} Selects whether their arrival time should be propagated together with the messages. Enabling this makes sense in order to keep the time stamp based message sorting intact. Note that IMAP does not guarantee that the time stamp (termed \fBinternal date\fR) is actually the arrival time, but it is usually close enough. (Default: \fBno\fR) . .P \fBSync\fR, \fBCreate\fR, \fBRemove\fR, \fBExpunge\fR, \fBMaxMessages\fR, and \fBCopyArrivalDate\fR can be used before any section for a global effect. The global settings are overridden by Channel-specific options, which in turn are overridden by command line switches. . .TP \fBSyncState\fR {\fB*\fR|\fIpath\fR} Set the location of this Channel's synchronization state files. \fB*\fR means that the state should be saved in a file named .mbsyncstate in the near side mailbox itself; this has the advantage that you do not need to handle the state file separately if you delete the mailbox, but it works only with Maildir mailboxes, obviously. Otherwise this is interpreted as a string to prepend to the near side mailbox name to make up a complete path. .br This option can be used outside any section for a global effect. In this case the appended string is made up according to the pattern \fB:\fIfar-store\fB:\fIfar-box\fB_:\fInear-store\fB:\fInear-box\fR (see also \fBFieldDelimiter\fR below). .br (Global default: \fI~/.mbsync/\fR). . .SS Groups .TP \fBGroup\fR \fIname\fR [\fIchannel\fR[\fB:\fIbox\fR[\fB,\fR...]]] ... Define the Group \fIname\fR, opening a section for its parameters. Note that even though Groups have an own namespace, they will "hide" Channels with the same name on the command line. .br One or more Channels can be specified on the same line. .br If you supply one or more \fIbox\fRes to a \fIchannel\fR, they will be used instead of what is specified in the Channel's Patterns. The same can be done on the command line, except that there newlines can be used as mailbox name separators as well. . .TP \fBChannel\fR[\fBs\fR] \fIchannel\fR[\fB:\fIbox\fR[\fB,\fR...]] ... Add the specified channels to the group. This option can be specified multiple times within a Group. . .SS Global Options .TP \fBFSync\fR \fByes\fR|\fBno\fR .br Selects whether \fBmbsync\fR performs forced flushing, which determines the level of data safety after system crashes and power outages. Disabling it is reasonably safe for file systems which are mounted with data=ordered mode. Enabling it is a wise choice for file systems mounted with data=writeback, in particular modern systems like ext4, btrfs and xfs. The performance impact on older file systems may be disproportionate. (Default: \fByes\fR) . .TP \fBFieldDelimiter\fR \fIdelim\fR The character to use to delimit fields in the string appended to a global \fBSyncState\fR. \fBmbsync\fR prefers to use the colon, but this is incompatible with DOS/Windows file systems. This option is meaningless for \fBSyncState\fR if the latter is \fB*\fR, obviously. However, it also determines the default of \fBInfoDelimiter\fR. (Global default: \fI;\fR on Windows, \fI:\fR everywhere else) . .TP \fBBufferLimit\fR \fIsize\fR[\fBk\fR|\fBm\fR][\fBb\fR] The per-Channel, per-direction instantaneous memory usage above which \fBmbsync\fR will refrain from using more memory. Note that this is no absolute limit, as even a single message can consume more memory than this. (Default: \fI10M\fR) . .SH CONSOLE OUTPUT If \fBmbsync\fR's output is connected to a console, it will print progress counters by default. The output will look like this: .P .in +4 C: 1/2 B: 3/4 F: +13/13 *23/42 #0/0 N: +0/7 *0/0 #0/0 .in -4 .P This represents the cumulative progress over channels, boxes, and messages affected on the far and near side, respectively. The message counts represent added messages, messages with updated flags, and trashed messages, respectively. No attempt is made to calculate the totals in advance, so they grow over time as more information is gathered. . .SH RECOMMENDATIONS Make sure your IMAP server does not auto-expunge deleted messages - it is slow, and semantically somewhat questionable. Specifically, Gmail needs to be configured not to do it. .P By default, \fBmbsync\fR will not delete any messages - deletions are propagated by marking the messages as deleted on the remote store. Once you have verified that your setup works, you will typically want to set \fBExpunge\fR to \fBBoth\fR, so that deletions become effective. .P \fBmbsync\fR's built-in trash functionality relies on \fBmbsync\fR doing the expunging of deleted messages. This is the case when it propagates deletions of previously propagated messages, and the trash is on the target store (typically your IMAP server). .br However, when you intend \fBmbsync\fR to trash messages which were not propagated yet, the MUA must mark the messages as deleted without expunging them (e.g., \fBMutt\fR's \fBmaildir_trash\fR option). Note that most messages are propagated a long time before they are deleted, so this is a corner case you probably do not want to optimize for. This also implies that the \fBTrashNewOnly\fR and \fBTrashRemoteNew\fR options are typically not very useful. .P If your server supports auto-trashing (as Gmail does), it is probably a good idea to rely on that instead of \fBmbsync\fR's trash functionality. If you do that, and intend to synchronize the trash like other mailboxes, you should not use \fBmbsync\fR's \fBTrash\fR option at all. .P Use of the \fBTrash\fR option with M$ Exchange 2013 requires the use of \fBDisableExtension MOVE\fR due to a server bug. .P When using the more efficient default UID mapping scheme, it is important that the MUA renames files when moving them between Maildir folders. Mutt always does that, while mu4e needs to be configured to do it: .br .in +4 (setq mu4e-change-filenames-when-moving t) .in -4 . .SH INHERENT PROBLEMS Changes done after \fBmbsync\fR has retrieved the message list will not be synchronised until the next time \fBmbsync\fR is invoked. .P Using \fBTrash\fR on IMAP Stores without the UIDPLUS extension (notably, M$ Exchange up to at least 2010) bears a race condition: messages will be lost if they are marked as deleted after the message list was retrieved but before the mailbox is expunged. There is no risk as long as the IMAP mailbox is accessed by only one client (including \fBmbsync\fR) at a time. . .SH FILES .TP .B ~/.mbsyncrc Default configuration file .TP .B ~/.mbsync/ Directory containing synchronization state files . .SH SEE ALSO mdconvert(1), mutt(1), maildir(5) .P Up to date information on \fBmbsync\fR can be found at http://isync.sf.net/ .P SASL mechanisms are listed at http://www.iana.org/assignments/sasl-mechanisms/sasl-mechanisms.xhtml . .SH AUTHORS Originally written by Michael R. Elkins, rewritten and currently maintained by Oswald Buddenhagen, contributions by Theodore Y. Ts'o. isync-1.4.4/src/drv_proxy_gen.pl0000755000175000001440000001265614006611550013606 00000000000000#!/usr/bin/perl # # mbsync - mailbox synchronizer # Copyright (C) 2017 Oswald Buddenhagen # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # As a special exception, mbsync may be linked with the OpenSSL library, # despite that library's more restrictive license. # use strict; use warnings; die("Usage: $0 driver.h drv_proxy.c drv_proxy.inc\n") if ($#ARGV != 2); my ($in_header, $in_source, $out_source) = @ARGV; my %templates; my %defines; my %excluded; my %special; open(my $ins, $in_source) or die("Cannot open $in_source: $!\n"); my $template; my $define; my $conts; while (<$ins>) { if ($template) { if (/^\/\/\# END$/) { $templates{$template} = $conts; $template = undef; } else { $conts .= $_; } } elsif ($define) { if (/^\/\/\# END$/) { $defines{$define} = $conts; $define = undef; } else { ($_ eq "\n") or s/^\t// or die("DEFINE content is not indented: $_"); $conts .= $_; } } else { if (/^\/\/\# TEMPLATE (\w+)$/) { $template = $1; $conts = ""; } elsif (/^\/\/\# DEFINE (\w+)$/) { $define = $1; $conts = ""; } elsif (/^\/\/\# DEFINE (\w+) (.*)$/) { $defines{$1} = $2; } elsif (/^\/\/\# UNDEFINE (\w+)$/) { $defines{$1} = ""; } elsif (/^\/\/\# EXCLUDE (\w+)$/) { $excluded{$1} = 1; } elsif (/^\/\/\# SPECIAL (\w+)$/) { $special{$1} = 1; } } } close($ins); open(my $inh, $in_header) or die("Cannot open $in_header: $!\n"); my $sts = 0; my $cont = ""; while (<$inh>) { if ($sts == 0) { if (/^struct driver \{$/) { $sts = 1; } } elsif ($sts == 1) { if (/^\};$/) { $sts = 0; } else { $cont .= $_; } } } close($inh); $cont =~ s,\n, ,g; $cont =~ s,/\*.*?\*/, ,g; $cont =~ s,\h+, ,g; my @ptypes = map { s,^ ,,r } split(/;/, $cont); pop @ptypes; # last one is empty my @cmd_table; sub make_args($) { $_ = shift; s/(?:^|(?<=, ))(?:const )?\w+ \*?//g; return $_; } sub type_to_format($) { $_ = shift; s/xint /\%\#x/g; s/uint /\%u/g; s/int /\%d/g; s/const char \*/\%s/g; return $_; } sub make_format($) { $_ = type_to_format(shift); s/, (\%\#?.)(\w+)/, $2=$1/g; return $_; } sub indent($$) { my ($str, $indent) = @_; return $str =~ s,^(?=.),$indent,smgr; } open(my $outh, ">".$out_source) or die("Cannot create $out_source: $!\n"); for (@ptypes) { /^([\w* ]+)\(\*(\w+)\)\( (.*) \)$/ or die("Cannot parse prototype '$_'\n"); my ($cmd_type, $cmd_name, $cmd_args) = ($1, $2, $3); if (defined($excluded{$cmd_name})) { push @cmd_table, "NULL"; next; } push @cmd_table, "proxy_$cmd_name"; next if (defined($special{$cmd_name})); my %replace; $replace{'name'} = $cmd_name; $replace{'type'} = $cmd_type; $cmd_args =~ s/^store_t \*ctx// or die("Arguments '$cmd_args' don't start with 'store_t *ctx'\n"); if ($cmd_name =~ /^get_/) { $template = "GETTER"; $replace{'fmt'} = type_to_format($cmd_type); } else { if ($cmd_type eq "void " && $cmd_args =~ s/, void \(\*cb\)\( (.*)void \*aux \), void \*aux$//) { my $cmd_cb_args = $1; if (length($cmd_cb_args)) { $replace{'decl_cb_args'} = $cmd_cb_args; my $r_cmd_cb_args = $cmd_cb_args; $r_cmd_cb_args =~ s/^int sts, // or die("Callback arguments of $cmd_name don't start with sts.\n"); $replace{'decl_cb_state'} = $r_cmd_cb_args =~ s/, /\;\n/gr; my $pass_cb_args = make_args($cmd_cb_args); $replace{'save_cb_args'} = $pass_cb_args =~ s/([^,]+), /cmd->$1 = $1\;\n/gr; $pass_cb_args =~ s/([^, ]+)/cmd->$1/g; $replace{'pass_cb_args'} = $pass_cb_args; $replace{'print_pass_cb_args'} = $pass_cb_args =~ s/(.*), $/, $1/r; $replace{'print_fmt_cb_args'} = make_format($cmd_cb_args =~ s/(.*), $/, $1/r); $replace{'gen_cmd_t'} = "gen_sts_cmd_t"; $replace{'GEN_CMD'} = "GEN_STS_CMD\n"; $replace{'gen_cmd'} = "&cmd->gen.gen"; } else { $replace{'gen_cmd_t'} = "gen_cmd_t"; $replace{'GEN_CMD'} = "GEN_CMD\n"; $replace{'gen_cmd'} = "&cmd->gen"; } $replace{'checked'} //= '0'; $template = "CALLBACK"; } elsif ($cmd_type eq "void ") { $template = "REGULAR_VOID"; } else { $template = "REGULAR"; $replace{'fmt'} = type_to_format($cmd_type); } $replace{'decl_args'} = $cmd_args; $replace{'print_pass_args'} = $replace{'pass_args'} = make_args($cmd_args); $replace{'print_fmt_args'} = make_format($cmd_args); } for (keys %defines) { $replace{$1} = delete $defines{$_} if (/^${cmd_name}_(.*)$/); } my %used; my $text = $templates{$template}; $text =~ s/^(\h*)\@(\w+)\@\n/$used{$2} = 1; indent($replace{$2} \/\/ "", $1)/smeg; $text =~ s/\@(\w+)\@/$used{$1} = 1; $replace{$1} \/\/ ""/eg; print $outh $text."\n"; my @not_used = grep { !defined($used{$_}) } keys %replace; die("Fatal: unconsumed replacements in $cmd_name: ".join(" ", @not_used)."\n") if (@not_used); } die("Fatal: unconsumed DEFINEs: ".join(" ", keys %defines)."\n") if (%defines); print $outh "struct driver proxy_driver = {\n".join("", map { "\t$_,\n" } @cmd_table)."};\n"; close $outh; isync-1.4.4/src/socket.c0000644000175000001440000006660314152373720012024 00000000000000/* * mbsync - mailbox synchronizer * Copyright (C) 2000-2002 Michael R. Elkins * Copyright (C) 2002-2006,2008,2010,2011, 2013 Oswald Buddenhagen * Copyright (C) 2004 Theodore Y. Ts'o * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * As a special exception, mbsync may be linked with the OpenSSL library, * despite that library's more restrictive license. */ #include "socket.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_LIBSSL # include # include # include # if OPENSSL_VERSION_NUMBER < 0x10100000L \ || (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070100fL) # define X509_OBJECT_get0_X509(o) ((o)->data.x509) # define X509_STORE_get0_objects(o) ((o)->objs) # endif #endif enum { SCK_CONNECTING, #ifdef HAVE_LIBSSL SCK_STARTTLS, #endif SCK_READY, SCK_EOF }; static void socket_fail( conn_t *conn ) { conn->bad_callback( conn->callback_aux ); } #ifdef HAVE_LIBSSL static void ATTR_PRINTFLIKE(1, 2) print_ssl_errors( const char *fmt, ... ) { char *action; va_list va; ulong err; va_start( va, fmt ); nfvasprintf( &action, fmt, va ); va_end( va ); while ((err = ERR_get_error())) error( "Error while %s: %s\n", action, ERR_error_string( err, NULL ) ); free( action ); } static int print_ssl_socket_errors( const char *func, conn_t *conn ) { ulong err; int num = 0; while ((err = ERR_get_error())) { error( "Socket error: secure %s %s: %s\n", func, conn->name, ERR_error_string( err, NULL ) ); num++; } return num; } static int ssl_return( const char *func, conn_t *conn, int ret ) { int err; switch ((err = SSL_get_error( conn->ssl, ret ))) { case SSL_ERROR_NONE: return ret; case SSL_ERROR_WANT_WRITE: conf_notifier( &conn->notify, POLLIN, POLLOUT ); FALLTHROUGH case SSL_ERROR_WANT_READ: return 0; case SSL_ERROR_SSL: print_ssl_socket_errors( func, conn ); break; case SSL_ERROR_SYSCALL: if (print_ssl_socket_errors( func, conn )) break; if (ret == 0) { case SSL_ERROR_ZERO_RETURN: /* Callers take the short path out, so signal higher layers from here. */ conn->state = SCK_EOF; conn->read_callback( conn->callback_aux ); return -1; } sys_error( "Socket error: secure %s %s", func, conn->name ); break; default: error( "Socket error: secure %s %s: unhandled SSL error %d\n", func, conn->name, err ); break; } if (conn->state == SCK_STARTTLS) conn->callbacks.starttls( 0, conn->callback_aux ); else socket_fail( conn ); return -1; } /* Some of this code is inspired by / lifted from mutt. */ static int host_matches( const char *host, const char *pattern ) { if (pattern[0] == '*' && pattern[1] == '.') { pattern += 2; if (!(host = strchr( host, '.' ))) return 0; host++; } return *host && *pattern && !strcasecmp( host, pattern ); } static int verify_hostname( X509 *cert, const char *hostname ) { int i, len, found; X509_NAME *subj; STACK_OF(GENERAL_NAME) *subj_alt_names; char cname[1000]; /* try the DNS subjectAltNames */ found = 0; if ((subj_alt_names = X509_get_ext_d2i( cert, NID_subject_alt_name, NULL, NULL ))) { int num_subj_alt_names = sk_GENERAL_NAME_num( subj_alt_names ); for (i = 0; i < num_subj_alt_names; i++) { GENERAL_NAME *subj_alt_name = sk_GENERAL_NAME_value( subj_alt_names, i ); if (subj_alt_name->type == GEN_DNS && strlen( (const char *)subj_alt_name->d.ia5->data ) == (size_t)subj_alt_name->d.ia5->length && host_matches( hostname, (const char *)(subj_alt_name->d.ia5->data) )) { found = 1; break; } } sk_GENERAL_NAME_pop_free( subj_alt_names, GENERAL_NAME_free ); } if (found) return 0; /* try the common name */ if (!(subj = X509_get_subject_name( cert ))) { error( "Error, cannot get certificate subject\n" ); return -1; } if ((len = X509_NAME_get_text_by_NID( subj, NID_commonName, cname, sizeof(cname) )) < 0) { error( "Error, cannot get certificate common name\n" ); return -1; } if (strlen( cname ) == (size_t)len && host_matches( hostname, cname )) return 0; error( "Error, certificate owner does not match hostname %s\n", hostname ); return -1; } static int verify_cert_host( const server_conf_t *conf, conn_t *sock ) { int i; long err; X509 *cert; cert = SSL_get_peer_certificate( sock->ssl ); if (!cert) { error( "Error, no server certificate\n" ); return -1; } for (i = 0; i < sk_X509_num( sock->conf->trusted_certs ); i++) { if (!X509_cmp( cert, sk_X509_value( sock->conf->trusted_certs, i ) )) { X509_free( cert ); return 0; } } err = SSL_get_verify_result( sock->ssl ); if (err != X509_V_OK) { error( "SSL error connecting %s: %s\n", sock->name, X509_verify_cert_error_string( err ) ); X509_free( cert ); return -1; } if (!conf->host) { error( "SSL error connecting %s: Neither host nor matching certificate specified\n", sock->name ); X509_free( cert ); return -1; } int ret = verify_hostname( cert, conf->host ); X509_free( cert ); return ret; } static int init_ssl_ctx( const server_conf_t *conf ) { DIAG_PUSH DIAG_DISABLE("-Wcast-qual") // C has no 'mutable' or const_cast<> ... server_conf_t *mconf = (server_conf_t *)conf; DIAG_POP if (conf->SSLContext) return conf->ssl_ctx_valid; #if OPENSSL_VERSION_NUMBER >= 0x10100000L const SSL_METHOD *method = TLS_client_method(); #else const SSL_METHOD *method = SSLv23_client_method(); #endif if (!(mconf->SSLContext = SSL_CTX_new( method ))) { print_ssl_errors( "initializing SSL context" ); return 0; } uint options = SSL_OP_NO_SSLv3; if (!(conf->ssl_versions & TLSv1)) options |= SSL_OP_NO_TLSv1; #ifdef SSL_OP_NO_TLSv1_1 if (!(conf->ssl_versions & TLSv1_1)) options |= SSL_OP_NO_TLSv1_1; #endif #ifdef SSL_OP_NO_TLSv1_2 if (!(conf->ssl_versions & TLSv1_2)) options |= SSL_OP_NO_TLSv1_2; #endif #ifdef SSL_OP_NO_TLSv1_3 if (!(conf->ssl_versions & TLSv1_3)) options |= SSL_OP_NO_TLSv1_3; #endif SSL_CTX_set_options( mconf->SSLContext, options ); if (conf->cipher_string && !SSL_CTX_set_cipher_list( mconf->SSLContext, conf->cipher_string )) { print_ssl_errors( "setting cipher string '%s'", conf->cipher_string ); return 0; } if (!(mconf->trusted_certs = sk_X509_new_null())) oom(); if (conf->cert_file) { X509_STORE *store; if (!(store = X509_STORE_new())) oom(); if (!X509_STORE_load_locations( store, conf->cert_file, NULL )) { print_ssl_errors( "loading certificate file '%s'", conf->cert_file ); return 0; } STACK_OF(X509_OBJECT) *objs = X509_STORE_get0_objects( store ); for (int i = 0; i < sk_X509_OBJECT_num( objs ); i++) { X509 *cert = X509_OBJECT_get0_X509( sk_X509_OBJECT_value( objs, i ) ); if (cert) { if (X509_check_ca( cert )) { if (!X509_STORE_add_cert( SSL_CTX_get_cert_store( mconf->SSLContext ), cert )) oom(); } else { X509_up_ref( cert ); // Locking failure assumed impossible if (!sk_X509_push( mconf->trusted_certs, cert )) oom(); } } } X509_STORE_free( store ); } if (mconf->system_certs && !SSL_CTX_set_default_verify_paths( mconf->SSLContext )) { ulong err; while ((err = ERR_get_error())) warn( "Warning: Unable to load default certificate files: %s\n", ERR_error_string( err, NULL ) ); } SSL_CTX_set_verify( mconf->SSLContext, SSL_VERIFY_NONE, NULL ); if (conf->client_certfile && !SSL_CTX_use_certificate_chain_file( mconf->SSLContext, conf->client_certfile)) { print_ssl_errors( "loading client certificate file '%s'", conf->client_certfile ); return 0; } if (conf->client_keyfile && !SSL_CTX_use_PrivateKey_file( mconf->SSLContext, conf->client_keyfile, SSL_FILETYPE_PEM)) { print_ssl_errors( "loading client private key '%s'", conf->client_keyfile ); return 0; } mconf->ssl_ctx_valid = 1; return 1; } static void start_tls_p2( conn_t * ); static void start_tls_p3( conn_t *, int ); static void ssl_fake_cb( void * ); void socket_start_tls( conn_t *conn, void (*cb)( int ok, void *aux ) ) { static int ssl_inited; conn->callbacks.starttls = cb; conn->state = SCK_STARTTLS; if (!ssl_inited) { SSL_library_init(); SSL_load_error_strings(); ssl_inited = 1; } if (!init_ssl_ctx( conn->conf )) { start_tls_p3( conn, 0 ); return; } init_wakeup( &conn->ssl_fake, ssl_fake_cb, conn ); if (!(conn->ssl = SSL_new( ((server_conf_t const *)conn->conf)->SSLContext ))) { print_ssl_errors( "initializing SSL connection" ); start_tls_p3( conn, 0 ); return; } if (!SSL_set_tlsext_host_name( conn->ssl, conn->conf->host )) { print_ssl_errors( "setting SSL server host name" ); start_tls_p3( conn, 0 ); return; } if (!SSL_set_fd( conn->ssl, conn->fd )) { print_ssl_errors( "setting SSL socket fd" ); start_tls_p3( conn, 0 ); return; } SSL_set_mode( conn->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER ); socket_expect_activity( conn, 1 ); start_tls_p2( conn ); } static void start_tls_p2( conn_t *conn ) { if (ssl_return( "connect to", conn, SSL_connect( conn->ssl ) ) > 0) { if (verify_cert_host( conn->conf, conn )) { start_tls_p3( conn, 0 ); } else { info( "Connection is now encrypted\n" ); start_tls_p3( conn, 1 ); } } } static void start_tls_p3( conn_t *conn, int ok ) { socket_expect_activity( conn, 0 ); conn->state = SCK_READY; conn->callbacks.starttls( ok, conn->callback_aux ); } #endif /* HAVE_LIBSSL */ #ifdef HAVE_LIBZ static void z_fake_cb( void * ); static const char * z_err_msg( int code, z_streamp strm ) { /* zlib's consistency in populating z_stream->msg is somewhat * less than stellar. zError() is undocumented. */ return strm->msg ? strm->msg : zError( code ); } void socket_start_deflate( conn_t *conn ) { int result; conn->in_z = nfcalloc( sizeof(*conn->in_z) ); result = inflateInit2( conn->in_z, -15 /* Use raw deflate */ ); if (result != Z_OK) { error( "Fatal: Cannot initialize decompression: %s\n", z_err_msg( result, conn->in_z ) ); abort(); } conn->out_z = nfcalloc( sizeof(*conn->out_z) ); result = deflateInit2( conn->out_z, Z_DEFAULT_COMPRESSION, /* Compression level */ Z_DEFLATED, /* Only valid value */ -15, /* Use raw deflate */ 8, /* Default memory usage */ Z_DEFAULT_STRATEGY /* Don't try to do anything fancy */ ); if (result != Z_OK) { error( "Fatal: Cannot initialize compression: %s\n", z_err_msg( result, conn->out_z ) ); abort(); } init_wakeup( &conn->z_fake, z_fake_cb, conn ); } #endif /* HAVE_LIBZ */ static void socket_fd_cb( int, void * ); static void socket_fake_cb( void * ); static void socket_timeout_cb( void * ); static void socket_connect_one( conn_t * ); static void socket_connect_next( conn_t * ); static void socket_connect_failed( conn_t * ); static void socket_connected( conn_t * ); static void socket_connect_bail( conn_t * ); static void socket_open_internal( conn_t *sock, int fd ) { sock->fd = fd; fcntl( fd, F_SETFL, O_NONBLOCK ); init_notifier( &sock->notify, fd, socket_fd_cb, sock ); init_wakeup( &sock->fd_fake, socket_fake_cb, sock ); init_wakeup( &sock->fd_timeout, socket_timeout_cb, sock ); } static void socket_close_internal( conn_t *sock ) { wipe_notifier( &sock->notify ); wipe_wakeup( &sock->fd_fake ); wipe_wakeup( &sock->fd_timeout ); close( sock->fd ); sock->fd = -1; } #ifndef HAVE_IPV6 struct addr_info { struct addr_info *ai_next; struct sockaddr_in ai_addr[1]; }; #define freeaddrinfo(ai) free( ai ) static struct addr_info * init_addrinfo( struct hostent *he ) { uint naddr = 0; for (char **addr = he->h_addr_list; *addr; addr++) naddr++; struct addr_info *caddr = nfcalloc( naddr * sizeof(struct addrinfo) ); struct addr_info *ret, **caddrp = &ret; for (char **addr = he->h_addr_list; *addr; addr++, caddr++) { caddr->ai_addr->sin_family = AF_INET; memcpy( &caddr->ai_addr->sin_addr.s_addr, *addr, sizeof(struct in_addr) ); *caddrp = caddr; caddrp = &caddr->ai_next; } return ret; } #endif void socket_connect( conn_t *sock, void (*cb)( int ok, void *aux ) ) { const server_conf_t *conf = sock->conf; sock->callbacks.connect = cb; /* open connection to server */ if (conf->tunnel) { int a[2]; nfasprintf( &sock->name, "tunnel '%s'", conf->tunnel ); infon( "Starting %s... ", sock->name ); if (socketpair( PF_UNIX, SOCK_STREAM, 0, a )) { perror( "socketpair" ); exit( 1 ); } if (fork() == 0) { if (dup2( a[0], 0 ) == -1 || dup2( a[0], 1 ) == -1) _exit( 127 ); close( a[0] ); close( a[1] ); execl( "/bin/sh", "sh", "-c", conf->tunnel, (char *)0 ); _exit( 127 ); } close( a[0] ); socket_open_internal( sock, a[1] ); info( "\vok\n" ); socket_connected( sock ); } else { #ifdef HAVE_IPV6 int gaierr; struct addrinfo hints; memset( &hints, 0, sizeof(hints) ); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_ADDRCONFIG; infon( "Resolving %s... ", conf->host ); if ((gaierr = getaddrinfo( conf->host, NULL, &hints, &sock->addrs ))) { error( "Error: Cannot resolve server '%s': %s\n", conf->host, gai_strerror( gaierr ) ); socket_connect_bail( sock ); return; } info( "\vok\n" ); #else struct hostent *he; infon( "Resolving %s... ", conf->host ); he = gethostbyname( conf->host ); if (!he) { error( "Error: Cannot resolve server '%s': %s\n", conf->host, hstrerror( h_errno ) ); socket_connect_bail( sock ); return; } info( "\vok\n" ); sock->addrs = init_addrinfo( he ); #endif sock->curr_addr = sock->addrs; socket_connect_one( sock ); } } static void socket_connect_one( conn_t *sock ) { int s; #ifdef HAVE_IPV6 struct addrinfo *ai; #else struct addr_info *ai; #endif if (!(ai = sock->curr_addr)) { error( "No working address found for %s\n", sock->conf->host ); socket_connect_bail( sock ); return; } #ifdef HAVE_IPV6 if (ai->ai_family == AF_INET6) { struct sockaddr_in6 *in6 = ((struct sockaddr_in6 *)ai->ai_addr); char sockname[64]; in6->sin6_port = htons( sock->conf->port ); nfasprintf( &sock->name, "%s ([%s]:%hu)", sock->conf->host, inet_ntop( AF_INET6, &in6->sin6_addr, sockname, sizeof(sockname) ), sock->conf->port ); } else #endif { struct sockaddr_in *in = ((struct sockaddr_in *)ai->ai_addr); in->sin_port = htons( sock->conf->port ); nfasprintf( &sock->name, "%s (%s:%hu)", sock->conf->host, inet_ntoa( in->sin_addr ), sock->conf->port ); } #ifdef HAVE_IPV6 s = socket( ai->ai_family, SOCK_STREAM, 0 ); #else s = socket( PF_INET, SOCK_STREAM, 0 ); #endif if (s < 0) { socket_connect_next( sock ); return; } socket_open_internal( sock, s ); infon( "Connecting to %s... ", sock->name ); #ifdef HAVE_IPV6 if (connect( s, ai->ai_addr, ai->ai_addrlen )) { #else if (connect( s, ai->ai_addr, sizeof(*ai->ai_addr) )) { #endif if (errno != EINPROGRESS) { socket_connect_failed( sock ); return; } conf_notifier( &sock->notify, 0, POLLOUT ); socket_expect_activity( sock, 1 ); sock->state = SCK_CONNECTING; info( "\v\n" ); return; } info( "\vok\n" ); socket_connected( sock ); } static void socket_connect_next( conn_t *conn ) { sys_error( "Cannot connect to %s", conn->name ); free( conn->name ); conn->name = NULL; conn->curr_addr = conn->curr_addr->ai_next; socket_connect_one( conn ); } static void socket_connect_failed( conn_t *conn ) { socket_close_internal( conn ); socket_connect_next( conn ); } static void socket_connected( conn_t *conn ) { if (conn->addrs) { freeaddrinfo( conn->addrs ); conn->addrs = NULL; } conf_notifier( &conn->notify, 0, POLLIN ); socket_expect_activity( conn, 0 ); conn->state = SCK_READY; conn->callbacks.connect( 1, conn->callback_aux ); } static void socket_cleanup_names( conn_t *conn ) { if (conn->addrs) { freeaddrinfo( conn->addrs ); conn->addrs = NULL; } free( conn->name ); conn->name = NULL; } static void socket_connect_bail( conn_t *conn ) { socket_cleanup_names( conn ); conn->callbacks.connect( 0, conn->callback_aux ); } static void dispose_chunk( conn_t *conn ); void socket_close( conn_t *sock ) { if (sock->fd >= 0) socket_close_internal( sock ); socket_cleanup_names( sock ); #ifdef HAVE_LIBSSL if (sock->ssl) { SSL_free( sock->ssl ); sock->ssl = NULL; wipe_wakeup( &sock->ssl_fake ); } #endif #ifdef HAVE_LIBZ if (sock->in_z) { inflateEnd( sock->in_z ); free( sock->in_z ); sock->in_z = NULL; deflateEnd( sock->out_z ); free( sock->out_z ); sock->out_z = NULL; wipe_wakeup( &sock->z_fake ); } #endif while (sock->write_buf) dispose_chunk( sock ); free( sock->append_buf ); sock->append_buf = NULL; } static int prepare_read( conn_t *sock, char **buf, uint *len ) { uint n = sock->offset + sock->bytes; if (!(*len = sizeof(sock->buf) - n)) { error( "Socket error: receive buffer full. Probably protocol error.\n" ); socket_fail( sock ); return -1; } *buf = sock->buf + n; return 0; } static int do_read( conn_t *sock, char *buf, uint len ) { int n; assert( sock->fd >= 0 ); #ifdef HAVE_LIBSSL if (sock->ssl) { if ((n = ssl_return( "read from", sock, SSL_read( sock->ssl, buf, (int)len ) )) <= 0) return n; if (n == (int)len && SSL_pending( sock->ssl )) conf_wakeup( &sock->ssl_fake, 0 ); } else #endif { if ((n = read( sock->fd, buf, len )) < 0) { sys_error( "Socket error: read from %s", sock->name ); socket_fail( sock ); } else if (!n) { /* EOF. Callers take the short path out, so signal higher layers from here. */ sock->state = SCK_EOF; sock->read_callback( sock->callback_aux ); } } return n; } #ifdef HAVE_LIBZ static void socket_fill_z( conn_t *sock ) { char *buf; uint len; int ret; if (prepare_read( sock, &buf, &len ) < 0) return; sock->in_z->avail_out = len; sock->in_z->next_out = (unsigned char *)buf; ret = inflate( sock->in_z, Z_SYNC_FLUSH ); /* Z_BUF_ERROR happens here when the previous call both consumed * all input and exactly filled up the output buffer. */ if (ret != Z_OK && ret != Z_BUF_ERROR && ret != Z_STREAM_END) { error( "Error decompressing data from %s: %s\n", sock->name, z_err_msg( ret, sock->in_z ) ); socket_fail( sock ); return; } if (!sock->in_z->avail_out) conf_wakeup( &sock->z_fake, 0 ); if ((len = (uint)((char *)sock->in_z->next_out - buf))) { sock->bytes += len; sock->read_callback( sock->callback_aux ); } } #endif static void socket_fill( conn_t *sock ) { #ifdef HAVE_LIBZ if (sock->in_z) { int ret; /* The timer will preempt reads until the buffer is empty. */ assert( !sock->in_z->avail_in ); sock->in_z->next_in = (uchar *)sock->z_buf; if ((ret = do_read( sock, sock->z_buf, sizeof(sock->z_buf) )) <= 0) return; sock->in_z->avail_in = (uint)ret; socket_fill_z( sock ); } else #endif { char *buf; uint len; if (prepare_read( sock, &buf, &len ) < 0) return; int n; if ((n = do_read( sock, buf, len )) <= 0) return; sock->bytes += (uint)n; sock->read_callback( sock->callback_aux ); } } void socket_expect_activity( conn_t *conn, int expect ) { if (conn->conf->timeout > 0 && expect != pending_wakeup( &conn->fd_timeout )) conf_wakeup( &conn->fd_timeout, expect ? conn->conf->timeout : -1 ); } int socket_read( conn_t *conn, char *buf, uint len ) { uint n = conn->bytes; if (!n && conn->state == SCK_EOF) return -1; if (n > len) n = len; memcpy( buf, conn->buf + conn->offset, n ); if (!(conn->bytes -= n)) conn->offset = 0; else conn->offset += n; return (int)n; } char * socket_read_line( conn_t *b ) { char *p, *s; uint n; s = b->buf + b->offset; p = memchr( s + b->scanoff, '\n', b->bytes - b->scanoff ); if (!p) { b->scanoff = b->bytes; if (b->offset + b->bytes == sizeof(b->buf)) { memmove( b->buf, b->buf + b->offset, b->bytes ); b->offset = 0; } if (b->state == SCK_EOF) return (void *)~0; return NULL; } n = (uint)(p + 1 - s); b->offset += n; b->bytes -= n; b->scanoff = 0; if (p != s && p[-1] == '\r') p--; *p = 0; return s; } static int do_write( conn_t *sock, char *buf, uint len ) { int n; assert( sock->fd >= 0 ); #ifdef HAVE_LIBSSL if (sock->ssl) return ssl_return( "write to", sock, SSL_write( sock->ssl, buf, (int)len ) ); #endif n = write( sock->fd, buf, len ); if (n < 0) { if (errno != EAGAIN && errno != EWOULDBLOCK) { sys_error( "Socket error: write to %s", sock->name ); socket_fail( sock ); } else { n = 0; conf_notifier( &sock->notify, POLLIN, POLLOUT ); } } else if (n != (int)len) { conf_notifier( &sock->notify, POLLIN, POLLOUT ); } return n; } static void dispose_chunk( conn_t *conn ) { buff_chunk_t *bc = conn->write_buf; if (!(conn->write_buf = bc->next)) conn->write_buf_append = &conn->write_buf; conn->buffer_mem -= bc->len; free( bc ); } static int do_queued_write( conn_t *conn ) { buff_chunk_t *bc; if (!conn->write_buf) return 0; while ((bc = conn->write_buf)) { int n; uint len = bc->len - conn->write_offset; if ((n = do_write( conn, bc->data + conn->write_offset, len )) < 0) return -1; if (n != (int)len) { conn->write_offset += (uint)n; return 0; } conn->write_offset = 0; dispose_chunk( conn ); } #ifdef HAVE_LIBSSL if (conn->ssl && SSL_pending( conn->ssl )) conf_wakeup( &conn->ssl_fake, 0 ); #endif conn->write_callback( conn->callback_aux ); return -1; } static void do_append( conn_t *conn, buff_chunk_t *bc ) { bc->next = NULL; conn->buffer_mem += bc->len; *conn->write_buf_append = bc; conn->write_buf_append = &bc->next; } /* This is big enough to avoid excessive chunking, but is * sufficiently small to keep SSL latency low with a slow uplink. */ #define WRITE_CHUNK_SIZE 1024 static void do_flush( conn_t *conn ) { buff_chunk_t *bc = conn->append_buf; #ifdef HAVE_LIBZ if (conn->out_z) { uint buf_avail = conn->append_avail; if (!conn->z_written) return; do { int ret; if (!bc) { buf_avail = WRITE_CHUNK_SIZE; bc = nfmalloc( offsetof(buff_chunk_t, data) + buf_avail ); bc->len = 0; } conn->out_z->next_in = Z_NULL; conn->out_z->avail_in = 0; conn->out_z->next_out = (uchar *)bc->data + bc->len; conn->out_z->avail_out = buf_avail; /* Z_BUF_ERROR cannot happen here, as zlib suppresses the error * both upon increasing the flush level (1st iteration) and upon * a no-op after the output buffer was full (later iterations). */ if ((ret = deflate( conn->out_z, Z_PARTIAL_FLUSH )) != Z_OK) { error( "Fatal: Compression error: %s\n", z_err_msg( ret, conn->out_z ) ); abort(); } bc->len = (uint)((char *)conn->out_z->next_out - bc->data); if (bc->len) { do_append( conn, bc ); bc = NULL; buf_avail = 0; } else { buf_avail = conn->out_z->avail_out; } } while (!conn->out_z->avail_out); conn->append_buf = bc; conn->append_avail = buf_avail; conn->z_written = 0; } else #endif if (bc) { do_append( conn, bc ); conn->append_buf = NULL; #ifdef HAVE_LIBZ conn->append_avail = 0; #endif } } void socket_write( conn_t *conn, conn_iovec_t *iov, int iovcnt ) { int i; uint buf_avail, len, offset = 0, total = 0; buff_chunk_t *bc; for (i = 0; i < iovcnt; i++) total += iov[i].len; if (total >= WRITE_CHUNK_SIZE) { /* If the new data is too big, queue the pending buffer to avoid latency. */ do_flush( conn ); } bc = conn->append_buf; #ifdef HAVE_LIBZ buf_avail = conn->append_avail; #endif while (total) { if (!bc) { /* We don't do anything special when compressing, as there is no way to * predict a reasonable output buffer size anyway - deflatePending() does * not account for consumed but not yet compressed input, and adding up * the deflateBound()s would be a tad *too* pessimistic. */ buf_avail = total > WRITE_CHUNK_SIZE ? total : WRITE_CHUNK_SIZE; bc = nfmalloc( offsetof(buff_chunk_t, data) + buf_avail ); bc->len = 0; #ifndef HAVE_LIBZ } else { /* A pending buffer will always be of standard size - over-sized * buffers are immediately filled and queued. */ buf_avail = WRITE_CHUNK_SIZE - bc->len; #endif } while (total) { len = iov->len - offset; #ifdef HAVE_LIBZ if (conn->out_z) { int ret; conn->out_z->next_in = (uchar *)iov->buf + offset; conn->out_z->avail_in = len; conn->out_z->next_out = (uchar *)bc->data + bc->len; conn->out_z->avail_out = buf_avail; /* Z_BUF_ERROR is impossible here, as the input buffer always has data, * and the output buffer always has space. */ if ((ret = deflate( conn->out_z, Z_NO_FLUSH )) != Z_OK) { error( "Fatal: Compression error: %s\n", z_err_msg( ret, conn->out_z ) ); abort(); } bc->len = (uint)((char *)conn->out_z->next_out - bc->data); buf_avail = conn->out_z->avail_out; len -= conn->out_z->avail_in; conn->z_written = 1; } else #endif { if (len > buf_avail) len = buf_avail; memcpy( bc->data + bc->len, iov->buf + offset, len ); bc->len += len; buf_avail -= len; } offset += len; total -= len; if (offset == iov->len) { if (iov->takeOwn == GiveOwn) free( iov->buf ); iov++; offset = 0; } if (!buf_avail) { do_append( conn, bc ); bc = NULL; break; } } } conn->append_buf = bc; #ifdef HAVE_LIBZ conn->append_avail = buf_avail; #endif conf_wakeup( &conn->fd_fake, 0 ); } static void socket_fd_cb( int events, void *aux ) { conn_t *conn = (conn_t *)aux; if ((events & POLLERR) || conn->state == SCK_CONNECTING) { int soerr; socklen_t selen = sizeof(soerr); if (getsockopt( conn->fd, SOL_SOCKET, SO_ERROR, &soerr, &selen )) { perror( "getsockopt" ); exit( 1 ); } errno = soerr; if (conn->state == SCK_CONNECTING) { if (errno) socket_connect_failed( conn ); else socket_connected( conn ); return; } sys_error( "Socket error from %s", conn->name ); socket_fail( conn ); return; } if (events & POLLOUT) conf_notifier( &conn->notify, POLLIN, 0 ); if (pending_wakeup( &conn->fd_timeout )) conf_wakeup( &conn->fd_timeout, conn->conf->timeout ); #ifdef HAVE_LIBSSL if (conn->ssl) { if (conn->state == SCK_STARTTLS) { start_tls_p2( conn ); return; } if (do_queued_write( conn ) < 0) return; socket_fill( conn ); return; } #endif if ((events & POLLOUT) && do_queued_write( conn ) < 0) return; if (events & POLLIN) socket_fill( conn ); } static void socket_fake_cb( void *aux ) { conn_t *conn = (conn_t *)aux; /* Ensure that a pending write gets queued. */ do_flush( conn ); /* If no writes are ongoing, start writing now. */ if (!(notifier_config( &conn->notify ) & POLLOUT)) do_queued_write( conn ); } static void socket_timeout_cb( void *aux ) { conn_t *conn = (conn_t *)aux; if (conn->state == SCK_CONNECTING) { errno = ETIMEDOUT; socket_connect_failed( conn ); } else { error( "Socket error on %s: timeout.\n", conn->name ); socket_fail( conn ); } } #ifdef HAVE_LIBZ static void z_fake_cb( void *aux ) { conn_t *conn = (conn_t *)aux; socket_fill_z( conn ); } #endif #ifdef HAVE_LIBSSL static void ssl_fake_cb( void *aux ) { conn_t *conn = (conn_t *)aux; socket_fill( conn ); } #endif isync-1.4.4/src/util.c0000644000175000001440000004104314152373720011500 00000000000000/* * mbsync - mailbox synchronizer * Copyright (C) 2000-2002 Michael R. Elkins * Copyright (C) 2002-2006,2011,2012 Oswald Buddenhagen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * As a special exception, mbsync may be linked with the OpenSSL library, * despite that library's more restrictive license. */ #include "common.h" #include #include #include #include #include #include #include #include #include static int need_nl; void flushn( void ) { if (need_nl) { putchar( '\n' ); fflush( stdout ); need_nl = 0; } } static void ATTR_PRINTFLIKE(1, 0) printn( const char *msg, va_list va ) { if (*msg == '\v') msg++; else flushn(); vprintf( msg, va ); fflush( stdout ); } void vdebug( int cat, const char *msg, va_list va ) { if (DFlags & cat) { vprintf( msg, va ); fflush( stdout ); need_nl = 0; } } void vdebugn( int cat, const char *msg, va_list va ) { if (DFlags & cat) { vprintf( msg, va ); fflush( stdout ); need_nl = 1; } } void progress( const char *msg, ... ) { va_list va; va_start( va, msg ); vprintf( msg, va ); va_end( va ); fflush( stdout ); need_nl = 1; } void info( const char *msg, ... ) { va_list va; if (DFlags & VERBOSE) { va_start( va, msg ); printn( msg, va ); va_end( va ); need_nl = 0; } } void infon( const char *msg, ... ) { va_list va; if (DFlags & VERBOSE) { va_start( va, msg ); printn( msg, va ); va_end( va ); need_nl = 1; } } void notice( const char *msg, ... ) { va_list va; if (!(DFlags & QUIET)) { va_start( va, msg ); printn( msg, va ); va_end( va ); need_nl = 0; } } void warn( const char *msg, ... ) { va_list va; if (!(DFlags & VERYQUIET)) { flushn(); va_start( va, msg ); vfprintf( stderr, msg, va ); va_end( va ); } } void error( const char *msg, ... ) { va_list va; flushn(); va_start( va, msg ); vfprintf( stderr, msg, va ); va_end( va ); } void vsys_error( const char *msg, va_list va ) { char buf[1024]; int errno_bak = errno; flushn(); if ((uint)vsnprintf( buf, sizeof(buf), msg, va ) >= sizeof(buf)) oob(); errno = errno_bak; perror( buf ); } void sys_error( const char *msg, ... ) { va_list va; va_start( va, msg ); vsys_error( msg, va ); va_end( va ); } void add_string_list_n( string_list_t **list, const char *str, uint len ) { string_list_t *elem; elem = nfmalloc( offsetof(string_list_t, string) + len + 1 ); elem->next = *list; *list = elem; memcpy( elem->string, str, len ); elem->string[len] = 0; } void add_string_list( string_list_t **list, const char *str ) { add_string_list_n( list, str, strlen( str ) ); } void free_string_list( string_list_t *list ) { string_list_t *tlist; for (; list; list = tlist) { tlist = list->next; free( list ); } } #ifndef HAVE_VASPRINTF static int vasprintf( char **strp, const char *fmt, va_list ap ) { int len; char tmp[1024]; if ((len = vsnprintf( tmp, sizeof(tmp), fmt, ap )) < 0 || !(*strp = malloc( len + 1 ))) return -1; if (len >= (int)sizeof(tmp)) vsprintf( *strp, fmt, ap ); else memcpy( *strp, tmp, (size_t)len + 1 ); return len; } #endif #ifndef HAVE_MEMRCHR void * memrchr( const void *s, int c, size_t n ) { u_char *b = (u_char *)s, *e = b + n; while (--e >= b) if (*e == c) return (void *)e; return 0; } #endif #ifndef HAVE_STRNLEN size_t strnlen( const char *str, size_t maxlen ) { const char *estr = memchr( str, 0, maxlen ); return estr ? (size_t)(estr - str) : maxlen; } #endif int starts_with( const char *str, int strl, const char *cmp, uint cmpl ) { if (strl < 0) strl = strnlen( str, cmpl + 1 ); return ((uint)strl >= cmpl) && !memcmp( str, cmp, cmpl ); } int starts_with_upper( const char *str, int strl, const char *cmp, uint cmpl ) { if (strl < 0) strl = strnlen( str, cmpl + 1 ); if ((uint)strl < cmpl) return 0; for (uint i = 0; i < cmpl; i++) if (str[i] != cmp[i] && toupper( str[i] ) != cmp[i]) return 0; return 1; } int equals( const char *str, int strl, const char *cmp, uint cmpl ) { if (strl < 0) strl = strnlen( str, cmpl + 1 ); return ((uint)strl == cmpl) && !memcmp( str, cmp, cmpl ); } #ifndef HAVE_TIMEGM /* Converts struct tm to time_t, assuming the data in tm is UTC rather than local timezone. mktime is similar but assumes struct tm, also known as the "broken-down" form of time, is in local time zone. timegm uses mktime to make the conversion understanding that an offset will be introduced by the local time assumption. mktime_from_utc then measures the introduced offset by applying gmtime to the initial result and applying mktime to the resulting "broken-down" form. The difference between the two mktime results is the measured offset which is then subtracted from the initial mktime result to yield a calendar time which is the value returned. tm_isdst in struct tm is set to 0 to force mktime to introduce a consistent offset (the non DST offset) since tm and tm+o might be on opposite sides of a DST change. Some implementations of mktime return -1 for the nonexistent localtime hour at the beginning of DST. In this event, use mktime(tm - 1hr) + 3600. Schematically mktime(tm) --> t+o gmtime(t+o) --> tm+o mktime(tm+o) --> t+2o t+o - (t+2o - t+o) = t Contributed by Roger Beeman , with the help of Mark Baushke and the rest of the Gurus at CISCO. Further improved by Roger with assistance from Edward J. Sabol based on input by Jamie Zawinski. */ static time_t my_mktime( struct tm *t ) { time_t tl = mktime( t ); if (tl == -1) { t->tm_hour--; tl = mktime( t ); if (tl != -1) tl += 3600; } return tl; } time_t timegm( struct tm *t ) { time_t tl, tb; struct tm *tg; if ((tl = my_mktime( t )) == -1) return tl; tg = gmtime( &tl ); tg->tm_isdst = 0; if ((tb = my_mktime( tg )) == -1) return tb; return tl - (tb - tl); } #endif void oob( void ) { fputs( "Fatal: buffer too small. Please report a bug.\n", stderr ); abort(); } int nfsnprintf( char *buf, int blen, const char *fmt, ... ) { int ret; va_list va; va_start( va, fmt ); if (blen <= 0 || (uint)(ret = vsnprintf( buf, (size_t)blen, fmt, va )) >= (uint)blen) oob(); va_end( va ); return ret; } void oom( void ) { fputs( "Fatal: Out of memory\n", stderr ); abort(); } void * nfmalloc( size_t sz ) { void *ret; if (!(ret = malloc( sz ))) oom(); return ret; } void * nfcalloc( size_t sz ) { void *ret; if (!(ret = calloc( sz, 1 ))) oom(); return ret; } void * nfrealloc( void *mem, size_t sz ) { char *ret; if (!(ret = realloc( mem, sz )) && sz) oom(); return ret; } char * nfstrndup( const char *str, size_t nchars ) { char *ret = nfmalloc( nchars + 1 ); memcpy( ret, str, nchars ); ret[nchars] = 0; return ret; } char * nfstrdup( const char *str ) { return nfstrndup( str, strlen( str ) ); } int nfvasprintf( char **str, const char *fmt, va_list va ) { int ret = vasprintf( str, fmt, va ); if (ret < 0) oom(); return ret; } int nfasprintf( char **str, const char *fmt, ... ) { int ret; va_list va; va_start( va, fmt ); ret = nfvasprintf( str, fmt, va ); va_end( va ); return ret; } /* static struct passwd * cur_user( void ) { char *p; struct passwd *pw; uid_t uid; uid = getuid(); if ((!(p = getenv("LOGNAME")) || !(pw = getpwnam( p )) || pw->pw_uid != uid) && (!(p = getenv("USER")) || !(pw = getpwnam( p )) || pw->pw_uid != uid) && !(pw = getpwuid( uid ))) { fputs ("Cannot determinate current user\n", stderr); return 0; } return pw; } */ char * expand_strdup( const char *s ) { struct passwd *pw; const char *p, *q; char *r; if (*s == '~') { s++; if (!*s) { p = NULL; q = Home; } else if (*s == '/') { p = s; q = Home; } else { if ((p = strchr( s, '/' ))) { r = nfstrndup( s, (size_t)(p - s) ); pw = getpwnam( r ); free( r ); } else pw = getpwnam( s ); if (!pw) return NULL; q = pw->pw_dir; } nfasprintf( &r, "%s%s", q, p ? p : "" ); return r; } else return nfstrdup( s ); } /* Return value: 0 = ok, -1 = out found in arg, -2 = in found in arg but no out specified */ int map_name( const char *arg, char **result, uint reserve, const char *in, const char *out ) { char *p; uint i, l, ll, num, inl, outl; assert( arg ); l = strlen( arg ); assert( in ); inl = strlen( in ); if (!inl) { copy: *result = nfmalloc( reserve + l + 1 ); memcpy( *result + reserve, arg, l + 1 ); return 0; } assert( out ); outl = strlen( out ); if (equals( in, (int)inl, out, outl )) goto copy; for (num = 0, i = 0; i < l; ) { for (ll = 0; ll < inl; ll++) if (arg[i + ll] != in[ll]) goto fout; num++; i += inl; continue; fout: if (outl) { for (ll = 0; ll < outl; ll++) if (arg[i + ll] != out[ll]) goto fnexti; return -1; } fnexti: i++; } if (!num) goto copy; if (!outl) return -2; *result = nfmalloc( reserve + l + num * (outl - inl) + 1 ); p = *result + reserve; for (i = 0; i < l; ) { for (ll = 0; ll < inl; ll++) if (arg[i + ll] != in[ll]) goto rnexti; memcpy( p, out, outl ); p += outl; i += inl; continue; rnexti: *p++ = arg[i++]; } *p = 0; return 0; } static int compare_uints( const void *l, const void *r ) { uint li = *(const uint *)l, ri = *(const uint *)r; if (li != ri) // Can't subtract, the result might not fit into signed int. return li > ri ? 1 : -1; return 0; } void sort_uint_array( uint_array_t array ) { qsort( array.data, array.size, sizeof(uint), compare_uints ); } int find_uint_array( uint_array_t array, uint value ) { uint bot = 0, top = array.size; while (bot < top) { uint i = (bot + top) / 2; uint elt = array.data[i]; if (elt == value) return 1; if (elt < value) bot = i + 1; else top = i; } return 0; } static struct { uchar i, j, s[256]; } rs; void arc4_init( void ) { int i, fd; uchar j, si, dat[128]; if ((fd = open( "/dev/urandom", O_RDONLY )) < 0 && (fd = open( "/dev/random", O_RDONLY )) < 0) { error( "Fatal: no random number source available.\n" ); exit( 3 ); } if (read( fd, dat, 128 ) != 128) { error( "Fatal: cannot read random number source.\n" ); exit( 3 ); } close( fd ); for (i = 0; i < 256; i++) rs.s[i] = (uchar)i; for (i = j = 0; i < 256; i++) { si = rs.s[i]; j += si + dat[i & 127]; rs.s[i] = rs.s[j]; rs.s[j] = si; } rs.i = rs.j = 0; for (i = 0; i < 256; i++) arc4_getbyte(); } uchar arc4_getbyte( void ) { uchar si, sj; rs.i++; si = rs.s[rs.i]; rs.j += si; sj = rs.s[rs.j]; rs.s[rs.i] = sj; rs.s[rs.j] = si; return rs.s[(si + sj) & 0xff]; } static const uchar prime_deltas[] = { 0, 0, 1, 3, 1, 5, 3, 3, 1, 9, 7, 5, 3, 17, 27, 3, 1, 29, 3, 21, 7, 17, 15, 9, 43, 35, 15, 0, 0, 0, 0, 0 }; uint bucketsForSize( uint size ) { uint base = 4, bits = 2; for (;;) { uint prime = base + prime_deltas[bits]; if (prime >= size) return prime; base <<= 1; bits++; } } static void list_prepend( list_head_t *head, list_head_t *to ) { assert( !head->next ); assert( to->next ); assert( to->prev->next == to ); head->next = to; head->prev = to->prev; head->prev->next = head; to->prev = head; } static void list_unlink( list_head_t *head ) { assert( head->next ); assert( head->next->prev == head); assert( head->prev->next == head); head->next->prev = head->prev; head->prev->next = head->next; head->next = head->prev = NULL; } static notifier_t *notifiers; static int changed; /* Iterator may be invalid now. */ #ifdef HAVE_POLL_H static struct pollfd *pollfds; static uint npolls, rpolls; #else # ifdef HAVE_SYS_SELECT_H # include # endif #endif void init_notifier( notifier_t *sn, int fd, void (*cb)( int, void * ), void *aux ) { #ifdef HAVE_POLL_H uint idx = npolls++; if (rpolls < npolls) { rpolls = npolls; pollfds = nfrealloc( pollfds, npolls * sizeof(*pollfds) ); } pollfds[idx].fd = fd; pollfds[idx].events = 0; /* POLLERR & POLLHUP implicit */ sn->index = idx; #else sn->fd = fd; sn->events = 0; #endif sn->cb = cb; sn->aux = aux; sn->next = notifiers; notifiers = sn; } void conf_notifier( notifier_t *sn, short and_events, short or_events ) { #ifdef HAVE_POLL_H uint idx = sn->index; pollfds[idx].events = (pollfds[idx].events & and_events) | or_events; #else sn->events = (sn->events & and_events) | or_events; #endif } short notifier_config( notifier_t *sn ) { #ifdef HAVE_POLL_H return pollfds[sn->index].events; #else return sn->events; #endif } void wipe_notifier( notifier_t *sn ) { notifier_t **snp; #ifdef HAVE_POLL_H uint idx; #endif for (snp = ¬ifiers; *snp != sn; snp = &(*snp)->next) assert( *snp ); *snp = sn->next; sn->next = NULL; changed = 1; #ifdef HAVE_POLL_H idx = sn->index; memmove( pollfds + idx, pollfds + idx + 1, (--npolls - idx) * sizeof(*pollfds) ); for (sn = notifiers; sn; sn = sn->next) { if (sn->index > idx) sn->index--; } #endif } static time_t get_now( void ) { return time( NULL ); } static list_head_t timers = { &timers, &timers }; void init_wakeup( wakeup_t *tmr, void (*cb)( void * ), void *aux ) { tmr->cb = cb; tmr->aux = aux; tmr->links.next = tmr->links.prev = NULL; } void wipe_wakeup( wakeup_t *tmr ) { if (tmr->links.next) list_unlink( &tmr->links ); } void conf_wakeup( wakeup_t *tmr, int to ) { list_head_t *head, *succ; if (to < 0) { if (tmr->links.next) list_unlink( &tmr->links ); } else { time_t timeout = to; if (!to) { /* We always prepend null timers, to cluster related events. */ succ = timers.next; } else { timeout += get_now(); /* We start at the end in the expectation that the newest timer is likely to fire last * (which will be true only if all timeouts are equal, but it's an as good guess as any). */ for (succ = &timers; (head = succ->prev) != &timers; succ = head) { if (head != &tmr->links && timeout > ((wakeup_t *)head)->timeout) break; } assert( head != &tmr->links ); } tmr->timeout = timeout; if (succ != &tmr->links) { if (tmr->links.next) list_unlink( &tmr->links ); list_prepend( &tmr->links, succ ); } } } static void event_wait( void ) { list_head_t *head; notifier_t *sn; int m; #ifdef HAVE_POLL_H int timeout = -1; if ((head = timers.next) != &timers) { wakeup_t *tmr = (wakeup_t *)head; time_t delta = tmr->timeout; if (!delta || (delta -= get_now()) <= 0) { list_unlink( head ); tmr->cb( tmr->aux ); return; } timeout = (int)delta * 1000; } switch (poll( pollfds, npolls, timeout )) { case 0: return; case -1: perror( "poll() failed in event loop" ); abort(); default: break; } for (sn = notifiers; sn; sn = sn->next) { uint n = sn->index; if ((m = pollfds[n].revents)) { assert( !(m & POLLNVAL) ); sn->cb( m | shifted_bit( m, POLLHUP, POLLIN ), sn->aux ); if (changed) { changed = 0; break; } } } #else struct timeval *timeout = 0; struct timeval to_tv; fd_set rfds, wfds, efds; int fd; if ((head = timers.next) != &timers) { wakeup_t *tmr = (wakeup_t *)head; time_t delta = tmr->timeout; if (!delta || (delta -= get_now()) <= 0) { list_unlink( head ); tmr->cb( tmr->aux ); return; } to_tv.tv_sec = delta; to_tv.tv_usec = 0; timeout = &to_tv; } FD_ZERO( &rfds ); FD_ZERO( &wfds ); FD_ZERO( &efds ); m = -1; for (sn = notifiers; sn; sn = sn->next) { fd = sn->fd; if (sn->events & POLLIN) FD_SET( fd, &rfds ); if (sn->events & POLLOUT) FD_SET( fd, &wfds ); FD_SET( fd, &efds ); if (fd > m) m = fd; } switch (select( m + 1, &rfds, &wfds, &efds, timeout )) { case 0: return; case -1: perror( "select() failed in event loop" ); abort(); default: break; } for (sn = notifiers; sn; sn = sn->next) { fd = sn->fd; m = 0; if (FD_ISSET( fd, &rfds )) m |= POLLIN; if (FD_ISSET( fd, &wfds )) m |= POLLOUT; if (FD_ISSET( fd, &efds )) m |= POLLERR; if (m) { sn->cb( m, sn->aux ); if (changed) { changed = 0; break; } } } #endif } void main_loop( void ) { while (notifiers || timers.next != &timers) event_wait(); } isync-1.4.4/src/drv_proxy.c0000644000175000001440000002667614006611550012570 00000000000000/* * mbsync - mailbox synchronizer * Copyright (C) 2017 Oswald Buddenhagen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * As a special exception, mbsync may be linked with the OpenSSL library, * despite that library's more restrictive license. */ #include "driver.h" #include #include #include typedef struct gen_cmd gen_cmd_t; typedef union proxy_store { store_t gen; struct { STORE(union proxy_store) const char *label; // foreign uint ref_count; driver_t *real_driver; store_t *real_store; gen_cmd_t *done_cmds, **done_cmds_append; gen_cmd_t *check_cmds, **check_cmds_append; wakeup_t wakeup; void (*bad_callback)( void *aux ); void *bad_callback_aux; }; } proxy_store_t; static void ATTR_PRINTFLIKE(1, 2) debug( const char *msg, ... ) { va_list va; va_start( va, msg ); vdebug( DEBUG_DRV, msg, va ); va_end( va ); } static void ATTR_PRINTFLIKE(1, 2) debugn( const char *msg, ... ) { va_list va; va_start( va, msg ); vdebugn( DEBUG_DRV, msg, va ); va_end( va ); } /* Keep the mailbox driver flag definitions in sync: */ /* grep for MAILBOX_DRIVER_FLAG */ /* The order is according to alphabetical maildir flag sort */ static const char Flags[] = { 'D', 'F', 'P', 'R', 'S', 'T' }; static char * proxy_make_flags( uchar flags, char *buf ) { uint i, d; for (d = 0, i = 0; i < as(Flags); i++) if (flags & (1 << i)) buf[d++] = Flags[i]; buf[d] = 0; return buf; } static void proxy_store_deref( proxy_store_t *ctx ) { if (!--ctx->ref_count) { assert( !pending_wakeup( &ctx->wakeup ) ); free( ctx ); } } static int curr_tag; #define GEN_CMD \ uint ref_count; \ int tag; \ proxy_store_t *ctx; \ gen_cmd_t *next; \ void (*queued_cb)( gen_cmd_t *gcmd ); struct gen_cmd { GEN_CMD }; #define GEN_STS_CMD \ GEN_CMD \ int sts; typedef union { gen_cmd_t gen; struct { GEN_STS_CMD }; } gen_sts_cmd_t; static gen_cmd_t * proxy_cmd_new( proxy_store_t *ctx, uint sz ) { gen_cmd_t *cmd = nfmalloc( sz ); cmd->ref_count = 2; cmd->tag = ++curr_tag; cmd->ctx = ctx; ctx->ref_count++; return cmd; } static void proxy_cmd_done( gen_cmd_t *cmd ) { if (!--cmd->ref_count) { proxy_store_deref( cmd->ctx ); free( cmd ); } } static void proxy_wakeup( void *aux ) { proxy_store_t *ctx = (proxy_store_t *)aux; gen_cmd_t *cmd = ctx->done_cmds; assert( cmd ); if (!(ctx->done_cmds = cmd->next)) ctx->done_cmds_append = &ctx->done_cmds; else conf_wakeup( &ctx->wakeup, 0 ); cmd->queued_cb( cmd ); proxy_cmd_done( cmd ); } static void proxy_invoke_cb( gen_cmd_t *cmd, void (*cb)( gen_cmd_t * ), int checked, const char *name ) { if (DFlags & FORCEASYNC) { debug( "%s[% 2d] Callback queue %s%s\n", cmd->ctx->label, cmd->tag, name, checked ? " (checked)" : "" ); cmd->queued_cb = cb; cmd->next = NULL; if (checked) { *cmd->ctx->check_cmds_append = cmd; cmd->ctx->check_cmds_append = &cmd->next; } else { *cmd->ctx->done_cmds_append = cmd; cmd->ctx->done_cmds_append = &cmd->next; conf_wakeup( &cmd->ctx->wakeup, 0 ); } } else { cb( cmd ); proxy_cmd_done( cmd ); } } static void proxy_flush_checked_cmds( proxy_store_t *ctx ) { if (ctx->check_cmds) { *ctx->done_cmds_append = ctx->check_cmds; ctx->done_cmds_append = ctx->check_cmds_append; ctx->check_cmds_append = &ctx->check_cmds; ctx->check_cmds = NULL; conf_wakeup( &ctx->wakeup, 0 ); } } static void proxy_cancel_checked_cmds( proxy_store_t *ctx ) { gen_cmd_t *cmd; while ((cmd = ctx->check_cmds)) { if (!(ctx->check_cmds = cmd->next)) ctx->check_cmds_append = &ctx->check_cmds; ((gen_sts_cmd_t *)cmd)->sts = DRV_CANCELED; cmd->queued_cb( cmd ); } } #if 0 //# TEMPLATE GETTER static @type@proxy_@name@( store_t *gctx ) { proxy_store_t *ctx = (proxy_store_t *)gctx; @type@rv = ctx->real_driver->@name@( ctx->real_store ); debug( "%sCalled @name@, ret=@fmt@\n", ctx->label, rv ); return rv; } //# END //# TEMPLATE REGULAR static @type@proxy_@name@( store_t *gctx@decl_args@ ) { proxy_store_t *ctx = (proxy_store_t *)gctx; @pre_print_args@ debug( "%sEnter @name@@print_fmt_args@\n", ctx->label@print_pass_args@ ); @print_args@ @type@rv = ctx->real_driver->@name@( ctx->real_store@pass_args@ ); debug( "%sLeave @name@, ret=@fmt@\n", ctx->label, rv ); return rv; } //# END //# TEMPLATE REGULAR_VOID static @type@proxy_@name@( store_t *gctx@decl_args@ ) { proxy_store_t *ctx = (proxy_store_t *)gctx; @pre_print_args@ debug( "%sEnter @name@@print_fmt_args@\n", ctx->label@print_pass_args@ ); @print_args@ ctx->real_driver->@name@( ctx->real_store@pass_args@ ); debug( "%sLeave @name@\n", ctx->label ); @action@ } //# END //# TEMPLATE CALLBACK typedef union { @gen_cmd_t@ gen; struct { @GEN_CMD@ @decl_cb_state@ void (*callback)( @decl_cb_args@void *aux ); void *callback_aux; @decl_state@ }; } @name@_cmd_t; static void proxy_do_@name@_cb( gen_cmd_t *gcmd ) { @name@_cmd_t *cmd = (@name@_cmd_t *)gcmd; @pre_print_cb_args@ debug( "%s[% 2d] Callback enter @name@@print_fmt_cb_args@\n", cmd->ctx->label, cmd->tag@print_pass_cb_args@ ); @print_cb_args@ cmd->callback( @pass_cb_args@cmd->callback_aux ); debug( "%s[% 2d] Callback leave @name@\n", cmd->ctx->label, cmd->tag ); } static void proxy_@name@_cb( @decl_cb_args@void *aux ) { @name@_cmd_t *cmd = (@name@_cmd_t *)aux; @save_cb_args@ proxy_invoke_cb( @gen_cmd@, proxy_do_@name@_cb, @checked@, "@name@" ); } static @type@proxy_@name@( store_t *gctx@decl_args@, void (*cb)( @decl_cb_args@void *aux ), void *aux ) { proxy_store_t *ctx = (proxy_store_t *)gctx; @name@_cmd_t *cmd = (@name@_cmd_t *)proxy_cmd_new( ctx, sizeof(@name@_cmd_t) ); cmd->callback = cb; cmd->callback_aux = aux; @assign_state@ @pre_print_args@ debug( "%s[% 2d] Enter @name@@print_fmt_args@\n", ctx->label, cmd->tag@print_pass_args@ ); @print_args@ ctx->real_driver->@name@( ctx->real_store@pass_args@, proxy_@name@_cb, cmd ); debug( "%s[% 2d] Leave @name@\n", ctx->label, cmd->tag ); proxy_cmd_done( @gen_cmd@ ); } //# END //# UNDEFINE list_store_print_fmt_cb_args //# UNDEFINE list_store_print_pass_cb_args //# DEFINE list_store_print_cb_args if (cmd->sts == DRV_OK) { for (string_list_t *box = cmd->boxes; box; box = box->next) debug( " %s\n", box->string ); } //# END //# DEFINE load_box_pre_print_args static char ubuf[12]; //# END //# DEFINE load_box_print_fmt_args , [%u,%s] (find >= %u, paired <= %u, new > %u) //# DEFINE load_box_print_pass_args , minuid, (maxuid == UINT_MAX) ? "inf" : (nfsnprintf( ubuf, sizeof(ubuf), "%u", maxuid ), ubuf), finduid, pairuid, newuid //# DEFINE load_box_print_args if (excs.size) { debugn( " excs:" ); for (uint t = 0; t < excs.size; t++) debugn( " %u", excs.data[t] ); debug( "\n" ); } //# END //# DEFINE load_box_print_fmt_cb_args , sts=%d, total=%d, recent=%d //# DEFINE load_box_print_pass_cb_args , cmd->sts, cmd->total_msgs, cmd->recent_msgs //# DEFINE load_box_print_cb_args if (cmd->sts == DRV_OK) { static char fbuf[as(Flags) + 1]; for (message_t *msg = cmd->msgs; msg; msg = msg->next) debug( " uid=%-5u flags=%-4s size=%-6u tuid=%." stringify(TUIDL) "s\n", msg->uid, (msg->status & M_FLAGS) ? (proxy_make_flags( msg->flags, fbuf ), fbuf) : "?", msg->size, *msg->tuid ? msg->tuid : "?" ); } //# END //# DEFINE find_new_msgs_print_fmt_cb_args , sts=%d //# DEFINE find_new_msgs_print_pass_cb_args , cmd->sts //# DEFINE find_new_msgs_print_cb_args if (cmd->sts == DRV_OK) { for (message_t *msg = cmd->msgs; msg; msg = msg->next) debug( " uid=%-5u tuid=%." stringify(TUIDL) "s\n", msg->uid, msg->tuid ); } //# END //# DEFINE fetch_msg_decl_state msg_data_t *data; //# END //# DEFINE fetch_msg_assign_state cmd->data = data; //# END //# DEFINE fetch_msg_print_fmt_args , uid=%u, want_flags=%s, want_date=%s //# DEFINE fetch_msg_print_pass_args , msg->uid, !(msg->status & M_FLAGS) ? "yes" : "no", data->date ? "yes" : "no" //# DEFINE fetch_msg_pre_print_cb_args static char fbuf[as(Flags) + 1]; proxy_make_flags( cmd->data->flags, fbuf ); //# END //# DEFINE fetch_msg_print_fmt_cb_args , flags=%s, date=%lld, size=%u //# DEFINE fetch_msg_print_pass_cb_args , fbuf, (long long)cmd->data->date, cmd->data->len //# DEFINE fetch_msg_print_cb_args if (cmd->sts == DRV_OK && (DFlags & DEBUG_DRV_ALL)) { printf( "%s=========\n", cmd->ctx->label ); fwrite( cmd->data->data, cmd->data->len, 1, stdout ); printf( "%s=========\n", cmd->ctx->label ); fflush( stdout ); } //# END //# DEFINE store_msg_pre_print_args static char fbuf[as(Flags) + 1]; proxy_make_flags( data->flags, fbuf ); //# END //# DEFINE store_msg_print_fmt_args , flags=%s, date=%lld, size=%u, to_trash=%s //# DEFINE store_msg_print_pass_args , fbuf, (long long)data->date, data->len, to_trash ? "yes" : "no" //# DEFINE store_msg_print_args if (DFlags & DEBUG_DRV_ALL) { printf( "%s>>>>>>>>>\n", ctx->label ); fwrite( data->data, data->len, 1, stdout ); printf( "%s>>>>>>>>>\n", ctx->label ); fflush( stdout ); } //# END //# DEFINE set_msg_flags_pre_print_args static char fbuf1[as(Flags) + 1], fbuf2[as(Flags) + 1]; proxy_make_flags( add, fbuf1 ); proxy_make_flags( del, fbuf2 ); //# END //# DEFINE set_msg_flags_print_fmt_args , uid=%u, add=%s, del=%s //# DEFINE set_msg_flags_print_pass_args , uid, fbuf1, fbuf2 //# DEFINE set_msg_flags_checked sts == DRV_OK //# DEFINE trash_msg_print_fmt_args , uid=%u //# DEFINE trash_msg_print_pass_args , msg->uid //# DEFINE commit_cmds_print_args proxy_flush_checked_cmds( ctx ); //# END //# DEFINE cancel_cmds_print_cb_args proxy_cancel_checked_cmds( cmd->ctx ); //# END //# DEFINE free_store_print_args proxy_cancel_checked_cmds( ctx ); //# END //# DEFINE free_store_action proxy_store_deref( ctx ); //# END //# DEFINE cancel_store_print_args proxy_cancel_checked_cmds( ctx ); //# END //# DEFINE cancel_store_action proxy_store_deref( ctx ); //# END #endif //# SPECIAL set_bad_callback static void proxy_set_bad_callback( store_t *gctx, void (*cb)( void *aux ), void *aux ) { proxy_store_t *ctx = (proxy_store_t *)gctx; ctx->bad_callback = cb; ctx->bad_callback_aux = aux; } static void proxy_invoke_bad_callback( proxy_store_t *ctx ) { ctx->ref_count++; debug( "%sCallback enter bad store\n", ctx->label ); ctx->bad_callback( ctx->bad_callback_aux ); debug( "%sCallback leave bad store\n", ctx->label ); proxy_store_deref( ctx ); } //# EXCLUDE alloc_store store_t * proxy_alloc_store( store_t *real_ctx, const char *label ) { proxy_store_t *ctx; ctx = nfcalloc( sizeof(*ctx) ); ctx->driver = &proxy_driver; ctx->gen.conf = real_ctx->conf; ctx->ref_count = 1; ctx->label = label; ctx->done_cmds_append = &ctx->done_cmds; ctx->check_cmds_append = &ctx->check_cmds; ctx->real_driver = real_ctx->driver; ctx->real_store = real_ctx; ctx->real_driver->set_bad_callback( ctx->real_store, (void (*)(void *))proxy_invoke_bad_callback, ctx ); init_wakeup( &ctx->wakeup, proxy_wakeup, ctx ); return &ctx->gen; } //# EXCLUDE parse_store //# EXCLUDE cleanup //# EXCLUDE get_fail_state #include "drv_proxy.inc" isync-1.4.4/src/Makefile.am0000644000175000001440000000162214006611550012404 00000000000000mbsync_SOURCES = main.c sync.c config.c util.c socket.c driver.c drv_imap.c drv_maildir.c drv_proxy.c mbsync_LDADD = $(DB_LIBS) $(SSL_LIBS) $(SOCK_LIBS) $(SASL_LIBS) $(Z_LIBS) $(KEYCHAIN_LIBS) noinst_HEADERS = common.h config.h driver.h sync.h socket.h drv_proxy.$(OBJEXT): drv_proxy.inc drv_proxy.inc: $(srcdir)/driver.h $(srcdir)/drv_proxy.c $(srcdir)/drv_proxy_gen.pl perl $(srcdir)/drv_proxy_gen.pl $(srcdir)/driver.h $(srcdir)/drv_proxy.c drv_proxy.inc mdconvert_SOURCES = mdconvert.c mdconvert_LDADD = $(DB_LIBS) if with_mdconvert mdconvert_prog = mdconvert mdconvert_man = mdconvert.1 endif EXTRA_PROGRAMS = tst_timers tst_timers_SOURCES = tst_timers.c util.c bin_PROGRAMS = mbsync $(mdconvert_prog) man_MANS = mbsync.1 $(mdconvert_man) exampledir = $(docdir)/examples example_DATA = mbsyncrc.sample EXTRA_DIST = drv_proxy_gen.pl run-tests.pl $(example_DATA) $(man_MANS) CLEANFILES = drv_proxy.inc isync-1.4.4/src/socket.h0000644000175000001440000001052514152373720012021 00000000000000/* * mbsync - mailbox synchronizer * Copyright (C) 2000-2002 Michael R. Elkins * Copyright (C) 2002-2006,2010-2012 Oswald Buddenhagen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * As a special exception, mbsync may be linked with the OpenSSL library, * despite that library's more restrictive license. */ #ifndef SOCKET_H #define SOCKET_H #include "common.h" #ifdef HAVE_LIBZ #include #endif #ifdef HAVE_LIBSSL # include # include enum { TLSv1 = 4, TLSv1_1 = 8, TLSv1_2 = 16, TLSv1_3 = 32 }; #endif typedef struct { char *tunnel; char *host; ushort port; int timeout; #ifdef HAVE_LIBSSL char *cert_file; char *client_certfile; char *client_keyfile; char *cipher_string; char system_certs; char ssl_versions; /* these are actually variables and are leaked at the end */ char ssl_ctx_valid; STACK_OF(X509) *trusted_certs; SSL_CTX *SSLContext; #endif } server_conf_t; typedef struct buff_chunk { struct buff_chunk *next; uint len; char data[1]; } buff_chunk_t; typedef struct { /* connection */ int fd; int state; const server_conf_t *conf; /* needed during connect */ #ifdef HAVE_IPV6 struct addrinfo *addrs, *curr_addr; /* needed during connect */ #else struct addr_info *addrs, *curr_addr; /* needed during connect */ #endif char *name; #ifdef HAVE_LIBSSL SSL *ssl; wakeup_t ssl_fake; #endif #ifdef HAVE_LIBZ z_streamp in_z, out_z; wakeup_t z_fake; int z_written; #endif void (*bad_callback)( void *aux ); /* async fail while sending or listening */ void (*read_callback)( void *aux ); /* data available for reading */ void (*write_callback)( void *aux ); /* all *queued* data was sent */ union { void (*connect)( int ok, void *aux ); void (*starttls)( int ok, void *aux ); } callbacks; void *callback_aux; notifier_t notify; wakeup_t fd_fake; wakeup_t fd_timeout; /* writing */ buff_chunk_t *append_buf; /* accumulating buffer */ buff_chunk_t *write_buf, **write_buf_append; /* buffer head & tail */ #ifdef HAVE_LIBZ uint append_avail; /* space left in accumulating buffer */ #endif uint write_offset; /* offset into buffer head */ uint buffer_mem; /* memory currently occupied by buffers in the queue */ /* reading */ uint offset; /* start of filled bytes in buffer */ uint bytes; /* number of filled bytes in buffer */ uint scanoff; /* offset to continue scanning for newline at, relative to 'offset' */ char buf[100000]; #ifdef HAVE_LIBZ char z_buf[100000]; #endif } conn_t; /* call this before doing anything with the socket */ static INLINE void socket_init( conn_t *conn, const server_conf_t *conf, void (*bad_callback)( void *aux ), void (*read_callback)( void *aux ), void (*write_callback)( void *aux ), void *aux ) { conn->conf = conf; conn->bad_callback = bad_callback; conn->read_callback = read_callback; conn->write_callback = write_callback; conn->callback_aux = aux; conn->fd = -1; conn->name = NULL; conn->write_buf_append = &conn->write_buf; } void socket_connect( conn_t *conn, void (*cb)( int ok, void *aux ) ); void socket_start_tls(conn_t *conn, void (*cb)( int ok, void *aux ) ); void socket_start_deflate( conn_t *conn ); void socket_close( conn_t *sock ); void socket_expect_activity( conn_t *sock, int expect ); int socket_read( conn_t *sock, char *buf, uint len ); /* never waits */ char *socket_read_line( conn_t *sock ); /* don't free return value; never waits */ typedef enum { KeepOwn = 0, GiveOwn } ownership_t; typedef struct { char *buf; uint len; ownership_t takeOwn; } conn_iovec_t; void socket_write( conn_t *sock, conn_iovec_t *iov, int iovcnt ); #endif isync-1.4.4/src/driver.h0000644000175000001440000002730014025155621012020 00000000000000/* * mbsync - mailbox synchronizer * Copyright (C) 2000-2002 Michael R. Elkins * Copyright (C) 2002-2006,2010-2012 Oswald Buddenhagen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * As a special exception, mbsync may be linked with the OpenSSL library, * despite that library's more restrictive license. */ #ifndef DRIVER_H #define DRIVER_H #include "config.h" typedef struct driver driver_t; #define FAIL_TEMP 0 /* Retry immediately (also: no error) */ #define FAIL_WAIT 1 /* Retry after some time (if at all) */ #define FAIL_FINAL 2 /* Don't retry until store reconfiguration */ #define STORE_CONF \ struct store_conf *next; \ char *name; \ driver_t *driver; \ const char *flat_delim; \ const char *map_inbox; \ const char *trash; \ uint max_size; /* off_t is overkill */ \ char trash_remote_new, trash_only_new; typedef struct store_conf { STORE_CONF } store_conf_t; /* For message->flags */ /* Keep the mailbox driver flag definitions in sync: */ /* grep for MAILBOX_DRIVER_FLAG */ /* The order is according to alphabetical maildir flag sort */ #define F_DRAFT (1<<0) /* Draft */ #define F_FLAGGED (1<<1) /* Flagged */ #define F_FORWARDED (1<<2) /* Passed */ #define F_ANSWERED (1<<3) /* Replied */ #define F_SEEN (1<<4) /* Seen */ #define F_DELETED (1<<5) /* Trashed */ #define NUM_FLAGS 6 /* For message->status */ #define M_RECENT (1<<0) /* unsyncable flag; maildir_* depend on this being 1<<0 */ #define M_DEAD (1<<1) /* expunged */ #define M_FLAGS (1<<2) /* flags fetched */ // The following are only for IMAP FETCH response parsing #define M_DATE (1<<3) #define M_SIZE (1<<4) #define M_BODY (1<<5) #define M_HEADER (1<<6) #define TUIDL 12 #define MESSAGE(message) \ message *next; \ struct sync_rec *srec; \ char *msgid; /* owned */ \ /* string_list_t *keywords; */ \ uint size; /* zero implies "not fetched" */ \ uint uid; \ uchar flags, status; \ char tuid[TUIDL]; typedef struct message { MESSAGE(struct message) } message_t; // For driver_t->prepare_load_box(), which may amend the passed flags. // The drivers don't use the first two, but may set them if loading the // particular range is required to handle some other flag; note that these // ranges may overlap. #define OPEN_OLD (1<<0) // Paired messages *in* this store. #define OPEN_NEW (1<<1) // Messages (possibly) not yet propagated *from* this store. #define OPEN_FLAGS (1<<2) // Note that fetch_msg() gets the flags regardless. #define OPEN_NEW_SIZE (1<<4) #define OPEN_EXPUNGE (1<<5) #define OPEN_SETFLAGS (1<<6) #define OPEN_APPEND (1<<7) #define OPEN_FIND (1<<8) #define OPEN_OLD_IDS (1<<9) #define UIDVAL_BAD ((uint)-1) #define STORE(store) \ store *next; \ driver_t *driver; \ store##_conf *conf; /* foreign */ typedef struct store { STORE(struct store) } store_t; typedef struct { char *data; uint len; time_t date; uchar flags; } msg_data_t; #define DRV_OK 0 /* Message went missing, or mailbox is full, etc. */ #define DRV_MSG_BAD 1 /* Something is wrong with the current mailbox - probably it is somehow inaccessible. */ #define DRV_BOX_BAD 2 /* Failed to connect store. */ #define DRV_STORE_BAD 3 /* The command has been cancel()ed or cancel_store()d. */ #define DRV_CANCELED 4 /* All memory belongs to the driver's user, unless stated otherwise. */ // If the driver is NOT DRV_ASYNC, memory owned by the driver returned // through callbacks MUST remain valid until a related subsequent command // is invoked, as the proxy driver may deliver these pointers with delay. /* This flag says that the driver CAN store messages with CRLFs, not that it must. The lack of it OTOH implies that it CANNOT, and as CRLF is the canonical format, we convert. */ #define DRV_CRLF 1 /* This flag says that the driver will act upon (DFlags & VERBOSE). */ #define DRV_VERBOSE 2 /* This flag says that the driver operates asynchronously. */ #define DRV_ASYNC 4 #define LIST_INBOX 1 #define LIST_PATH 2 #define LIST_PATH_MAYBE 4 #define xint uint // For auto-generation of appropriate printf() formats. struct driver { /* Return driver capabilities. */ xint (*get_caps)( store_t *ctx ); /* Parse configuration. */ int (*parse_store)( conffile_t *cfg, store_conf_t **storep ); /* Close remaining server connections. All stores must be discarded first. */ void (*cleanup)( void ); /* Allocate a store with the given configuration. This is expected to * return quickly, and must not fail. */ store_t *(*alloc_store)( store_conf_t *conf, const char *label ); /* When this callback is invoked (at most once per store), the store is fubar; * call cancel_store() to dispose of it. */ void (*set_bad_callback)( store_t *ctx, void (*cb)( void *aux ), void *aux ); /* Open/connect the store. This may recycle existing server connections. */ void (*connect_store)( store_t *ctx, void (*cb)( int sts, void *aux ), void *aux ); /* Discard the store. Underlying server connection may be kept alive. */ void (*free_store)( store_t *ctx ); /* Discard the store after a bad_callback. The server connections will be closed. * Pending commands will have their callbacks synchronously invoked with DRV_CANCELED. */ void (*cancel_store)( store_t *ctx ); /* List the mailboxes in this store. Flags are ORed LIST_* values. * The returned box list remains owned by the driver. */ void (*list_store)( store_t *ctx, int flags, void (*cb)( int sts, string_list_t *boxes, void *aux ), void *aux ); /* Invoked before open_box(), this informs the driver which box is to be opened. */ int (*select_box)( store_t *ctx, const char *name ); /* Get the selected box' on-disk path, if applicable, null otherwise. */ const char *(*get_box_path)( store_t *ctx ); /* Create the selected mailbox. */ void (*create_box)( store_t *ctx, void (*cb)( int sts, void *aux ), void *aux ); /* Open the selected mailbox. * Note that this should not directly complain about failure to open. */ void (*open_box)( store_t *ctx, void (*cb)( int sts, uint uidvalidity, void *aux ), void *aux ); /* Return the minimal UID the next stored message will have. */ uint (*get_uidnext)( store_t *ctx ); /* Return the flags that can be stored in the selected mailbox. */ xint (*get_supported_flags)( store_t *ctx ); /* Confirm that the open mailbox is empty. */ int (*confirm_box_empty)( store_t *ctx ); /* Delete the open mailbox. The mailbox is expected to be empty. * Subfolders of the mailbox are *not* deleted. * Some artifacts of the mailbox may remain, but they won't be * recognized as a mailbox any more. */ void (*delete_box)( store_t *ctx, void (*cb)( int sts, void *aux ), void *aux ); /* Remove the last artifacts of the open mailbox, as far as possible. */ int (*finish_delete_box)( store_t *ctx ); /* Invoked before load_box(), this informs the driver which operations (OP_*) * will be performed on the mailbox. The driver may extend the set by implicitly * needed or available operations. Returns this possibly extended set. */ xint (*prepare_load_box)( store_t *ctx, xint opts ); /* Load the message attributes needed to perform the requested operations. * Consider only messages with UIDs between minuid and maxuid (inclusive) * and those named in the excs array (smaller than minuid). * The driver takes ownership of the excs array. * Messages starting with finduid need to have the TUID populated when OPEN_FIND is set. * Messages up to pairuid need to have the Message-Id populated when OPEN_OLD_IDS is set. * Messages up to newuid need to have the size populated when OPEN_OLD_SIZE is set; * likewise messages above newuid when OPEN_NEW_SIZE is set. * The returned message list remains owned by the driver. */ void (*load_box)( store_t *ctx, uint minuid, uint maxuid, uint finduid, uint pairuid, uint newuid, uint_array_t excs, void (*cb)( int sts, message_t *msgs, int total_msgs, int recent_msgs, void *aux ), void *aux ); /* Fetch the contents and flags of the given message from the current mailbox. * If minimal is non-zero, fetch only a placeholder for the requested message - * ideally, this is precisely the header, but it may be more. */ void (*fetch_msg)( store_t *ctx, message_t *msg, msg_data_t *data, int minimal, void (*cb)( int sts, void *aux ), void *aux ); /* Store the given message to either the current mailbox or the trash folder. * If the new copy's UID can be immediately determined, return it, otherwise 0. */ void (*store_msg)( store_t *ctx, msg_data_t *data, int to_trash, void (*cb)( int sts, uint uid, void *aux ), void *aux ); /* Index the messages which have newly appeared in the mailbox, including their * temporary UID headers. This is needed if store_msg() does not guarantee returning * a UID; otherwise the driver needs to implement only the OPEN_FIND flag. * The returned message list remains owned by the driver. */ void (*find_new_msgs)( store_t *ctx, uint newuid, void (*cb)( int sts, message_t *msgs, void *aux ), void *aux ); /* Add/remove the named flags to/from the given message. The message may be either * a pre-fetched one (in which case the in-memory representation is updated), * or it may be identifed by UID only. The operation may be delayed until commit() * is called. */ void (*set_msg_flags)( store_t *ctx, message_t *msg, uint uid, int add, int del, void (*cb)( int sts, void *aux ), void *aux ); /* Move the given message from the current mailbox to the trash folder. * This may expunge the original message immediately, but it needn't to. */ void (*trash_msg)( store_t *ctx, message_t *msg, void (*cb)( int sts, void *aux ), void *aux ); /* Expunge deleted messages from the current mailbox and close it. * There is no need to explicitly close a mailbox if no expunge is needed. */ void (*close_box)( store_t *ctx, void (*cb)( int sts, void *aux ), void *aux ); /* Cancel queued commands which are not in flight yet; they will have their * callbacks invoked with DRV_CANCELED. Afterwards, wait for the completion of * the in-flight commands. If the store is canceled before this command completes, * the callback will *not* be invoked. */ void (*cancel_cmds)( store_t *ctx, void (*cb)( void *aux ), void *aux ); /* Commit any pending set_msg_flags() commands. */ void (*commit_cmds)( store_t *ctx ); /* Get approximate amount of memory occupied by the driver. */ uint (*get_memory_usage)( store_t *ctx ); /* Get the FAIL_* state of the driver. */ int (*get_fail_state)( store_conf_t *conf ); }; uint count_generic_messages( message_t * ); void free_generic_messages( message_t * ); void parse_generic_store( store_conf_t *store, conffile_t *cfg, const char *type ); store_t *proxy_alloc_store( store_t *real_ctx, const char *label ); #define N_DRIVERS 2 extern driver_t *drivers[N_DRIVERS]; extern driver_t maildir_driver, imap_driver, proxy_driver; #endif isync-1.4.4/src/run-tests.pl0000755000175000001440000004604414006611550012663 00000000000000#! /usr/bin/perl -w # # Copyright (C) 2006,2013 Oswald Buddenhagen # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # use warnings; use strict; use Cwd; use File::Path; use File::Temp 'tempdir'; my $use_vg = $ENV{USE_VALGRIND}; my $mbsync = getcwd()."/mbsync"; if (!-d "tmp") { unlink "tmp"; my $tdir = tempdir(); symlink $tdir, "tmp" or die "Cannot symlink temp directory: $!\n"; } chdir "tmp" or die "Cannot enter temp direcory.\n"; sub show($$$); sub test($$$$); ################################################################################ # Format of the test defs: [ far, near, state ] # far/near: [ maxuid, { seq, uid, flags }... ] # state: [ MaxPulledUid, MaxExpiredFarUid, MaxPushedUid, { muid, suid, flags }... ] use enum qw(:=1 A..Z); sub mn($) { chr(64 + shift) } # generic syncing tests my @x01 = ( [ 9, A, 1, "F", B, 2, "", C, 3, "FS", D, 4, "", E, 5, "T", F, 6, "F", G, 7, "FT", I, 9, "" ], [ 9, A, 1, "", B, 2, "F", C, 3, "F", D, 4, "", E, 5, "", G, 7, "", H, 8, "", J, 9, "" ], [ 8, 0, 0, 1, 1, "", 2, 2, "", 3, 3, "", 4, 4, "", 5, 5, "", 6, 6, "", 7, 7, "", 8, 8, "" ], ); my @O01 = ("", "", ""); #show("01", "01", "01"); my @X01 = ( [ 10, A, 1, "F", B, 2, "F", C, 3, "FS", D, 4, "", E, 5, "T", F, 6, "FT", G, 7, "FT", I, 9, "", J, 10, "" ], [ 10, A, 1, "F", B, 2, "F", C, 3, "FS", D, 4, "", E, 5, "T", G, 7, "FT", H, 8, "T", J, 9, "", I, 10, "" ], [ 10, 0, 10, 1, 1, "F", 2, 2, "F", 3, 3, "FS", 4, 4, "", 5, 5, "T", 6, 0, "", 7, 7, "FT", 0, 8, "", 10, 9, "", 9, 10, "" ], ); test("full", \@x01, \@X01, \@O01); my @O02 = ("", "", "Expunge Both\n"); #show("01", "02", "02"); my @X02 = ( [ 10, A, 1, "F", B, 2, "F", C, 3, "FS", D, 4, "", I, 9, "", J, 10, "" ], [ 10, A, 1, "F", B, 2, "F", C, 3, "FS", D, 4, "", J, 9, "", I, 10, "" ], [ 10, 0, 10, 1, 1, "F", 2, 2, "F", 3, 3, "FS", 4, 4, "", 10, 9, "", 9, 10, "" ], ); test("full + expunge both", \@x01, \@X02, \@O02); my @O03 = ("", "", "Expunge Near\n"); #show("01", "03", "03"); my @X03 = ( [ 10, A, 1, "F", B, 2, "F", C, 3, "FS", D, 4, "", E, 5, "T", F, 6, "FT", G, 7, "FT", I, 9, "", J, 10, "" ], [ 10, A, 1, "F", B, 2, "F", C, 3, "FS", D, 4, "", J, 9, "", I, 10, "" ], [ 10, 0, 10, 1, 1, "F", 2, 2, "F", 3, 3, "FS", 4, 4, "", 5, 0, "T", 6, 0, "", 7, 0, "T", 10, 9, "", 9, 10, "" ], ); test("full + expunge near side", \@x01, \@X03, \@O03); my @O04 = ("", "", "Sync Pull\n"); #show("01", "04", "04"); my @X04 = ( [ 9, A, 1, "F", B, 2, "", C, 3, "FS", D, 4, "", E, 5, "T", F, 6, "F", G, 7, "FT", I, 9, "" ], [ 10, A, 1, "F", B, 2, "F", C, 3, "FS", D, 4, "", E, 5, "T", G, 7, "FT", H, 8, "T", J, 9, "", I, 10, "" ], [ 9, 0, 0, 1, 1, "F", 2, 2, "", 3, 3, "FS", 4, 4, "", 5, 5, "T", 6, 6, "", 7, 7, "FT", 0, 8, "", 9, 10, "" ], ); test("pull", \@x01, \@X04, \@O04); my @O05 = ("", "", "Sync Flags\n"); #show("01", "05", "05"); my @X05 = ( [ 9, A, 1, "F", B, 2, "F", C, 3, "FS", D, 4, "", E, 5, "T", F, 6, "F", G, 7, "FT", I, 9, "" ], [ 9, A, 1, "F", B, 2, "F", C, 3, "FS", D, 4, "", E, 5, "T", G, 7, "FT", H, 8, "", J, 9, "" ], [ 8, 0, 0, 1, 1, "F", 2, 2, "F", 3, 3, "FS", 4, 4, "", 5, 5, "T", 6, 6, "", 7, 7, "FT", 8, 8, "" ], ); test("flags", \@x01, \@X05, \@O05); my @O06 = ("", "", "Sync Delete\n"); #show("01", "06", "06"); my @X06 = ( [ 9, A, 1, "F", B, 2, "", C, 3, "FS", D, 4, "", E, 5, "T", F, 6, "FT", G, 7, "FT", I, 9, "" ], [ 9, A, 1, "", B, 2, "F", C, 3, "F", D, 4, "", E, 5, "", G, 7, "", H, 8, "T", J, 9, "" ], [ 8, 0, 0, 1, 1, "", 2, 2, "", 3, 3, "", 4, 4, "", 5, 5, "", 6, 0, "", 7, 7, "", 0, 8, "" ], ); test("deletions", \@x01, \@X06, \@O06); my @O07 = ("", "", "Sync New\n"); #show("01", "07", "07"); my @X07 = ( [ 10, A, 1, "F", B, 2, "", C, 3, "FS", D, 4, "", E, 5, "T", F, 6, "F", G, 7, "FT", I, 9, "", J, 10, "" ], [ 10, A, 1, "", B, 2, "F", C, 3, "F", D, 4, "", E, 5, "", G, 7, "", H, 8, "", J, 9, "", I, 10, "" ], [ 10, 0, 10, 1, 1, "", 2, 2, "", 3, 3, "", 4, 4, "", 5, 5, "", 6, 6, "", 7, 7, "", 8, 8, "", 10, 9, "", 9, 10, "" ], ); test("new", \@x01, \@X07, \@O07); my @O08 = ("", "", "Sync PushFlags PullDelete\n"); #show("01", "08", "08"); my @X08 = ( [ 9, A, 1, "F", B, 2, "F", C, 3, "FS", D, 4, "", E, 5, "T", F, 6, "F", G, 7, "FT", I, 9, "" ], [ 9, A, 1, "", B, 2, "F", C, 3, "F", D, 4, "", E, 5, "", G, 7, "", H, 8, "T", J, 9, "" ], [ 8, 0, 0, 1, 1, "", 2, 2, "F", 3, 3, "F", 4, 4, "", 5, 5, "", 6, 6, "", 7, 7, "", 0, 8, "" ], ); test("push flags + pull deletions", \@x01, \@X08, \@O08); # size restriction tests my @x10 = ( [ 2, A, 1, "", B, 2, "*" ], [ 1, C, 1, "*" ], [ 0, 0, 0, ], ); my @O11 = ("MaxSize 1k\n", "MaxSize 1k\n", "Expunge Near"); #show("10", "11", "11"); my @X11 = ( [ 3, A, 1, "", B, 2, "*", C, 3, "?" ], [ 3, C, 1, "*", A, 2, "", B, 3, "?" ], [ 3, 0, 3, 3, 1, "<", 1, 2, "", 2, 3, ">" ], ); test("max size", \@x10, \@X11, \@O11); my @x22 = ( [ 3, A, 1, "", B, 2, "*", C, 3, "?" ], [ 3, C, 1, "F*", A, 2, "", B, 3, "F?" ], [ 3, 0, 3, 3, 1, "<", 1, 2, "", 2, 3, ">" ], ); #show("22", "22", "11"); my @X22 = ( [ 4, A, 1, "", B, 2, "*", C, 3, "T?", C, 4, "F*" ], [ 4, C, 1, "F*", A, 2, "", B, 4, "*" ], [ 4, 0, 4, 4, 1, "F", 3, 0, "T", 1, 2, "", 2, 4, "" ], ); test("max size + flagging", \@x22, \@X22, \@O11); my @x23 = ( [ 2, A, 1, "", B, 2, "F*" ], [ 1, C, 1, "F*" ], [ 0, 0, 0, ], ); my @X23 = ( [ 3, A, 1, "", B, 2, "F*", C, 3, "F*" ], [ 3, C, 1, "F*", A, 2, "", B, 3, "F*" ], [ 3, 0, 3, 3, 1, "F", 1, 2, "", 2, 3, "F" ] ); test("max size + initial flagging", \@x23, \@X23, \@O11); my @x24 = ( [ 3, A, 1, "", B, 2, "*", C, 3, "F*" ], [ 1, A, 1, "" ], [ 3, 0, 1, 1, 1, "", 2, 0, "^", 3, 0, "^" ], ); my @X24 = ( [ 3, A, 1, "", B, 2, "*", C, 3, "F*" ], [ 3, A, 1, "", B, 2, "?", C, 3, "F*" ], [ 3, 0, 3, 1, 1, "", 2, 2, ">", 3, 3, "F" ], ); test("max size (pre-1.4 legacy)", \@x24, \@X24, \@O11); # expiration tests my @x30 = ( [ 6, A, 1, "F", B, 2, "", C, 3, "S", D, 4, "", E, 5, "S", F, 6, "" ], [ 0, ], [ 0, 0, 0, ], ); my @O31 = ("", "", "MaxMessages 3\n"); #show("30", "31", "31"); my @X31 = ( [ 6, A, 1, "F", B, 2, "", C, 3, "S", D, 4, "", E, 5, "S", F, 6, "" ], [ 5, A, 1, "F", B, 2, "", D, 3, "", E, 4, "S", F, 5, "" ], [ 6, 3, 5, 1, 1, "F", 2, 2, "", 4, 3, "", 5, 4, "S", 6, 5, "" ], ); test("max messages", \@x30, \@X31, \@O31); my @O32 = ("", "", "MaxMessages 3\nExpireUnread yes\n"); #show("30", "32", "32"); my @X32 = ( [ 6, A, 1, "F", B, 2, "", C, 3, "S", D, 4, "", E, 5, "S", F, 6, "" ], [ 4, A, 1, "F", D, 2, "", E, 3, "S", F, 4, "" ], [ 6, 3, 4, 1, 1, "F", 4, 2, "", 5, 3, "S", 6, 4, "" ], ); test("max messages vs. unread", \@x30, \@X32, \@O32); my @x50 = ( [ 6, A, 1, "FS", B, 2, "FS", C, 3, "S", D, 4, "", E, 5, "", F, 6, "" ], [ 6, A, 1, "S", B, 2, "ST", D, 4, "", E, 5, "", F, 6, "" ], [ 6, 3, 0, 1, 1, "FS", 2, 2, "~S", 3, 3, "~S", 4, 4, "", 5, 5, "", 6, 6, "" ], ); my @O51 = ("", "", "MaxMessages 3\nExpunge Both\n"); #show("50", "51", "51"); my @X51 = ( [ 6, A, 1, "S", B, 2, "FS", C, 3, "S", D, 4, "", E, 5, "", F, 6, "" ], [ 6, B, 2, "FS", D, 4, "", E, 5, "", F, 6, "" ], [ 6, 3, 6, 2, 2, "FS", 4, 4, "", 5, 5, "", 6, 6, "" ], ); test("max messages + expunge", \@x50, \@X51, \@O51); ################################################################################ print "OK.\n"; exit 0; sub qm($) { shift; s/\\/\\\\/g; s/\"/\\"/g; s/\"/\\"/g; s/\n/\\n/g; return $_; } # [ $far, $near, $channel ] sub writecfg($) { my ($sfx) = @_; open(FILE, ">", ".mbsyncrc") or die "Cannot open .mbsyncrc.\n"; print FILE "FSync no MaildirStore far Path ./ Inbox ./far ".$$sfx[0]." MaildirStore near Path ./ Inbox ./near ".$$sfx[1]." Channel test Far :far: Near :near: SyncState * ".$$sfx[2]; close FILE; } sub killcfg() { unlink $_ for (glob("*.log")); unlink ".mbsyncrc"; } # $run_async, $mbsync_options, $log_file # Return: $exit_code, \@mbsync_output sub runsync($$$) { my ($async, $flags, $file) = @_; my $cmd; if ($use_vg) { $cmd = "valgrind -q --error-exitcode=1 "; } else { $flags .= " -D"; } $flags .= " -Ta" if ($async); $cmd .= "$mbsync -Tz $flags -c .mbsyncrc test"; open FILE, "$cmd 2>&1 |"; my @out = ; close FILE or push(@out, $! ? "*** error closing mbsync: $!\n" : "*** mbsync exited with signal ".($?&127).", code ".($?>>8)."\n"); if ($file) { open FILE, ">$file" or die("Cannot create $file: $!\n"); print FILE @out; close FILE; } return $?, \@out; } # $path # Return: $max_uid, { uid => [ seq, flags ] } sub readbox($) { my $bn = shift; (-d $bn) or die "No mailbox '$bn'.\n"; (-d $bn."/tmp" and -d $bn."/new" and -d $bn."/cur") or die "Invalid mailbox '$bn'.\n"; open(FILE, "<", $bn."/.uidvalidity") or die "Cannot read UID validity of mailbox '$bn'.\n"; my $dummy = ; chomp(my $mu = ); close FILE; my %ms = (); for my $d ("cur", "new") { opendir(DIR, $bn."/".$d) or next; for my $f (grep(!/^\.\.?$/, readdir(DIR))) { my ($uid, $flg, $ph, $num); if ($f =~ /^\d+\.\d+_\d+\.[-[:alnum:]]+,U=(\d+):2,(.*)$/) { ($uid, $flg) = ($1, $2); } else { print STDERR "unrecognided file name '$f' in '$bn'.\n"; exit 1; } open(FILE, "<", $bn."/".$d."/".$f) or die "Cannot read message '$f' in '$bn'.\n"; my $sz = 0; while () { /^Subject: (\[placeholder\] )?(\d+)$/ && ($ph = defined($1), $num = $2); $sz += length($_); } close FILE; if (!defined($num)) { print STDERR "message '$f' in '$bn' has no identifier.\n"; exit 1; } @{ $ms{$uid} } = ($num, $flg.($sz>1000?"*":"").($ph?"?":"")); } } return $mu, \%ms; } # $boxname # Output: # [ maxuid, # serial, uid, "flags", ... ], sub showbox($) { my ($bn) = @_; my ($mu, $ms) = readbox($bn); my @bc = ($mu); for my $uid (sort { $a <=> $b } keys %$ms) { push @bc, $$ms{$uid}[0], $uid, $$ms{$uid}[1]; } printbox(\@bc); } # $filename # Output: # [ maxuid[F], maxxfuid, maxuid[N], # uid[F], uid[N], "flags", ... ], sub showstate($) { my ($fn) = @_; if (!open(FILE, "<", $fn)) { print STDERR " Cannot read sync state $fn: $!\n"; return; } chomp(my @ls = ); close FILE; my %hdr; OUTER: while (1) { while (@ls) { $_ = shift(@ls); last OUTER if (!length($_)); if (!/^([^ ]+) (\d+)$/) { print STDERR "Malformed sync state header entry: $_\n"; close FILE; return; } $hdr{$1} = $2; } print STDERR "Unterminated sync state header.\n"; close FILE; return; } my @T = ($hdr{'MaxPulledUid'} // "missing", $hdr{'MaxExpiredFarUid'} // "0", $hdr{'MaxPushedUid'} // "missing"); for (@ls) { /^(\d+) (\d+) (.*)$/; push @T, $1, $2, $3; } printstate(\@T); } # $filename sub showchan($) { my ($fn) = @_; showbox("far"); showbox("near"); showstate($fn); } # $source_state_name, $target_state_name, $configs_name sub show($$$) { my ($sx, $tx, $sfxn) = @_; my ($sp, $sfx); eval "\$sp = \\\@x$sx"; eval "\$sfx = \\\@O$sfxn"; mkchan($$sp[0], $$sp[1], $$sp[2]); print "my \@x$sx = (\n"; showchan("near/.mbsyncstate"); print ");\n"; writecfg($sfx); runsync(0, "", ""); killcfg(); print "my \@X$tx = (\n"; showchan("near/.mbsyncstate"); print ");\n"; print "test(\"\", \\\@x$sx, \\\@X$tx, \\\@O$sfxn);\n\n"; rmtree "near"; rmtree "far"; } # $box_name, \@box_state sub mkbox($$) { my ($bn, $bs) = @_; rmtree($bn); (mkdir($bn) and mkdir($bn."/tmp") and mkdir($bn."/new") and mkdir($bn."/cur")) or die "Cannot create mailbox $bn.\n"; open(FILE, ">", $bn."/.uidvalidity") or die "Cannot create UID validity for mailbox $bn.\n"; print FILE "1\n$$bs[0]\n"; close FILE; for (my $i = 1; $i < @$bs; $i += 3) { my ($num, $uid, $flg) = ($$bs[$i], $$bs[$i + 1], $$bs[$i + 2]); my $big = $flg =~ s/\*//; my $ph = $flg =~ s/\?//; open(FILE, ">", $bn."/".($flg =~ /S/ ? "cur" : "new")."/0.1_".$num.".local,U=".$uid.":2,".$flg) or die "Cannot create message ".mn($num)." in mailbox $bn.\n"; print FILE "From: foo\nTo: bar\nDate: Thu, 1 Jan 1970 00:00:00 +0000\nSubject: ".($ph?"[placeholder] ":"").$num."\n\n".(("A"x50)."\n")x($big*30); close FILE; } } # \@far_state, \@near_state, \@sync_state sub mkchan($$$) { my ($f, $n, $t) = @_; mkbox("far", $f); mkbox("near", $n); open(FILE, ">", "near/.mbsyncstate") or die "Cannot create sync state.\n"; print FILE "FarUidValidity 1\nMaxPulledUid ".$$t[0]."\n". "NearUidValidity 1\nMaxExpiredFarUid ".$$t[1]."\nMaxPushedUid ".$$t[2]."\n\n"; for (my $i = 3; $i < @$t; $i += 3) { print FILE $$t[$i]." ".$$t[$i + 1]." ".$$t[$i + 2]."\n"; } close FILE; } # $box_name, \@box_state sub ckbox($$) { my ($bn, $bs) = @_; my ($mu, $ms) = readbox($bn); if ($mu != $$bs[0]) { print STDERR "MAXUID mismatch for '$bn' (got $mu, wanted $$bs[0]).\n"; return 1; } for (my $i = 1; $i < @$bs; $i += 3) { my ($num, $uid, $flg) = ($$bs[$i], $$bs[$i + 1], $$bs[$i + 2]); my $m = delete $$ms{$uid}; if (!defined $m) { print STDERR "No message $bn:$uid.\n"; return 1; } if ($$m[0] ne $num) { print STDERR "Subject mismatch for $bn:$uid.\n"; return 1; } if ($$m[1] ne $flg) { print STDERR "Flag mismatch for $bn:$uid.\n"; return 1; } } if (%$ms) { print STDERR "Excess messages in '$bn': ".join(", ", sort({ $a <=> $b } keys(%$ms))).".\n"; return 1; } return 0; } # $state_file, \@sync_state sub ckstate($$) { my ($fn, $t) = @_; my %hdr; $hdr{'FarUidValidity'} = "1"; $hdr{'NearUidValidity'} = "1"; $hdr{'MaxPulledUid'} = $$t[0]; $hdr{'MaxPushedUid'} = $$t[2]; $hdr{'MaxExpiredFarUid'} = $$t[1] if ($$t[1] ne 0); open(FILE, "<", $fn) or die "Cannot read sync state $fn.\n"; chomp(my @ls = ); close FILE; OUTER: while (1) { while (@ls) { my $l = shift(@ls); last OUTER if (!length($l)); if ($l !~ /^([^ ]+) (\d+)$/) { print STDERR "Malformed sync state header entry: $l\n"; return 1; } my $want = delete $hdr{$1}; if (!defined($want)) { print STDERR "Unexpected sync state header entry: $1\n"; return 1; } if ($2 != $want) { print STDERR "Sync state header entry $1 mismatch: got $2, wanted $want\n"; return 1; } } print STDERR "Unterminated sync state header.\n"; return 1; } my @ky = keys %hdr; if (@ky) { print STDERR "Keys missing from sync state header: @ky\n"; return 1; } my $i = 3; for my $l (@ls) { if ($i == @$t) { print STDERR "Excess sync state entry: '$l'.\n"; return 1; } my $xl = $$t[$i]." ".$$t[$i + 1]." ".$$t[$i + 2]; if ($l ne $xl) { print STDERR "Sync state entry mismatch: '$l' instead of '$xl'.\n"; return 1; } $i += 3; } if ($i < @$t) { print STDERR "Missing sync state entry: '".$$t[$i]." ".$$t[$i + 1]." ".$$t[$i + 2]."'.\n"; return 1; } return 0; } # $state_file, \@chan_state sub ckchan($$) { my ($fn, $cs) = @_; my $rslt = ckstate($fn, $$cs[2]); $rslt |= ckbox("far", $$cs[0]); $rslt |= ckbox("near", $$cs[1]); return $rslt; } # \@box_state sub printbox($) { my ($bs) = @_; print " [ $$bs[0],\n "; my $frst = 1; for (my $i = 1; $i < @$bs; $i += 3) { if ($frst) { $frst = 0; } else { print ", "; } print mn($$bs[$i]).", ".$$bs[$i + 1].", \"".$$bs[$i + 2]."\""; } print " ],\n"; } # \@sync_state sub printstate($) { my ($t) = @_; print " [ ".$$t[0].", ".$$t[1].", ".$$t[2].",\n "; my $frst = 1; for (my $i = 3; $i < @$t; $i += 3) { if ($frst) { $frst = 0; } else { print ", "; } print(($$t[$i] // "??").", ".($$t[$i + 1] // "??").", \"".($$t[$i + 2] // "??")."\""); } print " ],\n"; } # \@chan_state sub printchan($) { my ($cs) = @_; printbox($$cs[0]); printbox($$cs[1]); printstate($$cs[2]); } sub readfile($) { my ($file) = @_; open(FILE, $file) or return; my @nj = ; close FILE; return \@nj; } # $run_async, \@source_state, \@target_state, \@channel_configs sub test_impl($$$$) { my ($async, $sx, $tx, $sfx) = @_; mkchan($$sx[0], $$sx[1], $$sx[2]); my ($xc, $ret) = runsync($async, "-Tj", "1-initial.log"); if ($xc || ckchan("near/.mbsyncstate.new", $tx)) { print "Input:\n"; printchan($sx); print "Options:\n"; print " [ ".join(", ", map('"'.qm($_).'"', @$sfx))." ]\n"; if (!$xc) { print "Expected result:\n"; printchan($tx); print "Actual result:\n"; showchan("near/.mbsyncstate.new"); } print "Debug output:\n"; print @$ret; exit 1; } my $nj = readfile("near/.mbsyncstate.journal"); my ($jxc, $jret) = runsync($async, "-0 --no-expunge", "2-replay.log"); if ($jxc || ckstate("near/.mbsyncstate", $$tx[2])) { print "Journal replay failed.\n"; print "Options:\n"; print " [ ".join(", ", map('"'.qm($_).'"', @$sfx))." ], [ \"-0\", \"--no-expunge\" ]\n"; print "Old State:\n"; printstate($$sx[2]); print "Journal:\n".join("", @$nj)."\n"; if (!$jxc) { print "Expected New State:\n"; printstate($$tx[2]); print "New State:\n"; showstate("near/.mbsyncstate"); } print "Debug output:\n"; print @$jret; exit 1; } my ($ixc, $iret) = runsync($async, "", "3-verify.log"); if ($ixc || ckchan("near/.mbsyncstate", $tx)) { print "Idempotence verification run failed.\n"; print "Input == Expected result:\n"; printchan($tx); print "Options:\n"; print " [ ".join(", ", map('"'.qm($_).'"', @$sfx))." ]\n"; if (!$ixc) { print "Actual result:\n"; showchan("near/.mbsyncstate"); } print "Debug output:\n"; print @$iret; exit 1; } rmtree "near"; rmtree "far"; my $njl = (@$nj - 1) * 2; for (my $l = 1; $l <= $njl; $l++) { mkchan($$sx[0], $$sx[1], $$sx[2]); my ($nxc, $nret) = runsync($async, "-Tj$l", "4-interrupt.log"); if ($nxc != (100 + ($l & 1)) << 8) { print "Interrupting at step $l/$njl failed.\n"; print "Debug output:\n"; print @$nret; exit 1; } ($nxc, $nret) = runsync($async, "-Tj", "5-resume.log"); if ($nxc || ckchan("near/.mbsyncstate.new", $tx)) { print "Resuming from step $l/$njl failed.\n"; print "Input:\n"; printchan($sx); print "Options:\n"; print " [ ".join(", ", map('"'.qm($_).'"', @$sfx))." ]\n"; my $nnj = readfile("near/.mbsyncstate.journal"); my $ln = int($l / 2); print "Journal:\n".join("", @$nnj[0..$ln])."-------\n".join("", @$nnj[($ln + 1)..$#$nnj])."\n"; print "Full journal:\n".join("", @$nj)."\n"; if (!$nxc) { print "Expected result:\n"; printchan($tx); print "Actual result:\n"; showchan("near/.mbsyncstate.new"); } print "Debug output:\n"; print @$nret; exit 1; } rmtree "near"; rmtree "far"; } } # $title, \@source_state, \@target_state, \@channel_configs sub test($$$$) { my ($ttl, $sx, $tx, $sfx) = @_; return 0 if (scalar(@ARGV) && !grep { $_ eq $ttl } @ARGV); print "Testing: ".$ttl." ...\n"; writecfg($sfx); test_impl(0, $sx, $tx, $sfx); test_impl(1, $sx, $tx, $sfx); killcfg(); } isync-1.4.4/src/mdconvert.10000644000175000001440000000311114006611550012426 00000000000000.ig \" mdconvert - Maildir mailbox UID storage scheme converter \" Copyright (C) 2004 Oswald Buddenhagen \" \" This program is free software; you can redistribute it and/or modify \" it under the terms of the GNU General Public License as published by \" the Free Software Foundation; either version 2 of the License, or \" (at your option) any later version. \" \" This program is distributed in the hope that it will be useful, \" but WITHOUT ANY WARRANTY; without even the implied warranty of \" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the \" GNU General Public License for more details. \" \" You should have received a copy of the GNU General Public License \" along with this program. If not, see . .. .TH mdconvert 1 "2004 Mar 27" .. .SH NAME mdconvert - Maildir mailbox UID storage scheme converter .. .SH SYNOPSIS \fBmdconvert\fR [\fIoptions\fR ...] \fImailbox\fR ... .. .SH DESCRIPTION \fBmdconvert\fR converts Maildir mailboxes between the two UID storage schemes supported by \fBmbsync\fR. See \fBmbsync\fR's manual page for details on these schemes. .. .SH OPTIONS .TP \fB-a\fR, \fB--alt\fR Convert to the \fBalternative\fR (Berkeley DB based) UID storage scheme. .TP \fB-n\fR, \fB--native\fR Convert to the \fBnative\fR (file name based) UID storage scheme. This is the default. .TP \fB-h\fR, \fB--help\fR Displays a summary of command line options. .TP \fB-v\fR, \fB--version\fR Displays version information. .. .SH SEE ALSO mbsync(1) .. .SH AUTHOR Written and maintained by Oswald Buddenhagen . isync-1.4.4/src/Makefile.in0000644000175000001440000006257014152373730012435 00000000000000# Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 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@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) 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@ target_triplet = @target@ EXTRA_PROGRAMS = tst_timers$(EXEEXT) bin_PROGRAMS = mbsync$(EXEEXT) $(am__EXEEXT_1) subdir = src ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \ $(am__DIST_COMMON) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/autodefs.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = @with_mdconvert_TRUE@am__EXEEXT_1 = mdconvert$(EXEEXT) am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" \ "$(DESTDIR)$(exampledir)" PROGRAMS = $(bin_PROGRAMS) am_mbsync_OBJECTS = main.$(OBJEXT) sync.$(OBJEXT) config.$(OBJEXT) \ util.$(OBJEXT) socket.$(OBJEXT) driver.$(OBJEXT) \ drv_imap.$(OBJEXT) drv_maildir.$(OBJEXT) drv_proxy.$(OBJEXT) mbsync_OBJECTS = $(am_mbsync_OBJECTS) am__DEPENDENCIES_1 = mbsync_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) am_mdconvert_OBJECTS = mdconvert.$(OBJEXT) mdconvert_OBJECTS = $(am_mdconvert_OBJECTS) mdconvert_DEPENDENCIES = $(am__DEPENDENCIES_1) am_tst_timers_OBJECTS = tst_timers.$(OBJEXT) util.$(OBJEXT) tst_timers_OBJECTS = $(am_tst_timers_OBJECTS) tst_timers_LDADD = $(LDADD) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__maybe_remake_depfiles = depfiles am__depfiles_remade = ./$(DEPDIR)/config.Po ./$(DEPDIR)/driver.Po \ ./$(DEPDIR)/drv_imap.Po ./$(DEPDIR)/drv_maildir.Po \ ./$(DEPDIR)/drv_proxy.Po ./$(DEPDIR)/main.Po \ ./$(DEPDIR)/mdconvert.Po ./$(DEPDIR)/socket.Po \ ./$(DEPDIR)/sync.Po ./$(DEPDIR)/tst_timers.Po \ ./$(DEPDIR)/util.Po am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(mbsync_SOURCES) $(mdconvert_SOURCES) $(tst_timers_SOURCES) DIST_SOURCES = $(mbsync_SOURCES) $(mdconvert_SOURCES) \ $(tst_timers_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } man1dir = $(mandir)/man1 NROFF = nroff MANS = $(man_MANS) DATA = $(example_DATA) HEADERS = $(noinst_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DB_LIBS = @DB_LIBS@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ KEYCHAIN_LIBS = @KEYCHAIN_LIBS@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ 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@ PERL = @PERL@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ SASL_LIBS = @SASL_LIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOCK_LIBS = @SOCK_LIBS@ SSL_LIBS = @SSL_LIBS@ STRIP = @STRIP@ VERSION = @VERSION@ Z_LIBS = @Z_LIBS@ 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@ 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@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ mbsync_SOURCES = main.c sync.c config.c util.c socket.c driver.c drv_imap.c drv_maildir.c drv_proxy.c mbsync_LDADD = $(DB_LIBS) $(SSL_LIBS) $(SOCK_LIBS) $(SASL_LIBS) $(Z_LIBS) $(KEYCHAIN_LIBS) noinst_HEADERS = common.h config.h driver.h sync.h socket.h mdconvert_SOURCES = mdconvert.c mdconvert_LDADD = $(DB_LIBS) @with_mdconvert_TRUE@mdconvert_prog = mdconvert @with_mdconvert_TRUE@mdconvert_man = mdconvert.1 tst_timers_SOURCES = tst_timers.c util.c man_MANS = mbsync.1 $(mdconvert_man) exampledir = $(docdir)/examples example_DATA = mbsyncrc.sample EXTRA_DIST = drv_proxy_gen.pl run-tests.pl $(example_DATA) $(man_MANS) CLEANFILES = drv_proxy.inc all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(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) --gnu src/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/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__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ 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): install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) mbsync$(EXEEXT): $(mbsync_OBJECTS) $(mbsync_DEPENDENCIES) $(EXTRA_mbsync_DEPENDENCIES) @rm -f mbsync$(EXEEXT) $(AM_V_CCLD)$(LINK) $(mbsync_OBJECTS) $(mbsync_LDADD) $(LIBS) mdconvert$(EXEEXT): $(mdconvert_OBJECTS) $(mdconvert_DEPENDENCIES) $(EXTRA_mdconvert_DEPENDENCIES) @rm -f mdconvert$(EXEEXT) $(AM_V_CCLD)$(LINK) $(mdconvert_OBJECTS) $(mdconvert_LDADD) $(LIBS) tst_timers$(EXEEXT): $(tst_timers_OBJECTS) $(tst_timers_DEPENDENCIES) $(EXTRA_tst_timers_DEPENDENCIES) @rm -f tst_timers$(EXEEXT) $(AM_V_CCLD)$(LINK) $(tst_timers_OBJECTS) $(tst_timers_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/config.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/driver.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/drv_imap.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/drv_maildir.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/drv_proxy.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mdconvert.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/socket.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sync.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tst_timers.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util.Po@am__quote@ # am--include-marker $(am__depfiles_remade): @$(MKDIR_P) $(@D) @echo '# dummy' >$@-t && $(am__mv) $@-t $@ am--depfiles: $(am__depfiles_remade) .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` install-man1: $(man_MANS) @$(NORMAL_INSTALL) @list1=''; \ list2='$(man_MANS)'; \ test -n "$(man1dir)" \ && test -n "`echo $$list1$$list2`" \ || exit 0; \ echo " $(MKDIR_P) '$(DESTDIR)$(man1dir)'"; \ $(MKDIR_P) "$(DESTDIR)$(man1dir)" || exit 1; \ { for i in $$list1; do echo "$$i"; done; \ if test -n "$$list2"; then \ for i in $$list2; do echo "$$i"; done \ | sed -n '/\.1[a-z]*$$/p'; \ fi; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \ done; } uninstall-man1: @$(NORMAL_UNINSTALL) @list=''; test -n "$(man1dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \ sed -n '/\.1[a-z]*$$/p'; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ dir='$(DESTDIR)$(man1dir)'; $(am__uninstall_files_from_dir) install-exampleDATA: $(example_DATA) @$(NORMAL_INSTALL) @list='$(example_DATA)'; test -n "$(exampledir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(exampledir)'"; \ $(MKDIR_P) "$(DESTDIR)$(exampledir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(exampledir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(exampledir)" || exit $$?; \ done uninstall-exampleDATA: @$(NORMAL_UNINSTALL) @list='$(example_DATA)'; test -n "$(exampledir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(exampledir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(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 $(PROGRAMS) $(MANS) $(DATA) $(HEADERS) installdirs: for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(exampledir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done 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: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) 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-binPROGRAMS clean-generic mostlyclean-am distclean: distclean-am -rm -f ./$(DEPDIR)/config.Po -rm -f ./$(DEPDIR)/driver.Po -rm -f ./$(DEPDIR)/drv_imap.Po -rm -f ./$(DEPDIR)/drv_maildir.Po -rm -f ./$(DEPDIR)/drv_proxy.Po -rm -f ./$(DEPDIR)/main.Po -rm -f ./$(DEPDIR)/mdconvert.Po -rm -f ./$(DEPDIR)/socket.Po -rm -f ./$(DEPDIR)/sync.Po -rm -f ./$(DEPDIR)/tst_timers.Po -rm -f ./$(DEPDIR)/util.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-exampleDATA install-man install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-man1 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 ./$(DEPDIR)/config.Po -rm -f ./$(DEPDIR)/driver.Po -rm -f ./$(DEPDIR)/drv_imap.Po -rm -f ./$(DEPDIR)/drv_maildir.Po -rm -f ./$(DEPDIR)/drv_proxy.Po -rm -f ./$(DEPDIR)/main.Po -rm -f ./$(DEPDIR)/mdconvert.Po -rm -f ./$(DEPDIR)/socket.Po -rm -f ./$(DEPDIR)/sync.Po -rm -f ./$(DEPDIR)/tst_timers.Po -rm -f ./$(DEPDIR)/util.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-exampleDATA \ uninstall-man uninstall-man: uninstall-man1 .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-binPROGRAMS clean-generic cscopelist-am ctags ctags-am \ distclean distclean-compile distclean-generic distclean-tags \ distdir dvi dvi-am html html-am info info-am install \ install-am install-binPROGRAMS install-data install-data-am \ install-dvi install-dvi-am install-exampleDATA install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-man1 install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-binPROGRAMS uninstall-exampleDATA \ uninstall-man uninstall-man1 .PRECIOUS: Makefile drv_proxy.$(OBJEXT): drv_proxy.inc drv_proxy.inc: $(srcdir)/driver.h $(srcdir)/drv_proxy.c $(srcdir)/drv_proxy_gen.pl perl $(srcdir)/drv_proxy_gen.pl $(srcdir)/driver.h $(srcdir)/drv_proxy.c drv_proxy.inc # 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: isync-1.4.4/src/sync.c0000644000175000001440000022222414152373720011501 00000000000000/* * mbsync - mailbox synchronizer * Copyright (C) 2000-2002 Michael R. Elkins * Copyright (C) 2002-2006,2010-2013 Oswald Buddenhagen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * As a special exception, mbsync may be linked with the OpenSSL library, * despite that library's more restrictive license. */ #include "sync.h" #include #include #include #include #include #include #include #include #include #include #include #include #if !defined(_POSIX_SYNCHRONIZED_IO) || _POSIX_SYNCHRONIZED_IO <= 0 # define fdatasync fsync #endif #define JOURNAL_VERSION "4" channel_conf_t global_conf; channel_conf_t *channels; group_conf_t *groups; const char *str_fn[] = { "far side", "near side" }, *str_hl[] = { "push", "pull" }; static void ATTR_PRINTFLIKE(1, 2) debug( const char *msg, ... ) { va_list va; va_start( va, msg ); vdebug( DEBUG_SYNC, msg, va ); va_end( va ); } static void ATTR_PRINTFLIKE(1, 2) debugn( const char *msg, ... ) { va_list va; va_start( va, msg ); vdebugn( DEBUG_SYNC, msg, va ); va_end( va ); } static void Fclose( FILE *f, int safe ) { if ((safe && (fflush( f ) || (UseFSync && fdatasync( fileno( f ) )))) || fclose( f ) == EOF) { sys_error( "Error: cannot close file" ); exit( 1 ); } } static void ATTR_PRINTFLIKE(2, 0) vFprintf( FILE *f, const char *msg, va_list va ) { int r; r = vfprintf( f, msg, va ); if (r < 0) { sys_error( "Error: cannot write file" ); exit( 1 ); } } static void ATTR_PRINTFLIKE(2, 3) Fprintf( FILE *f, const char *msg, ... ) { va_list va; va_start( va, msg ); vFprintf( f, msg, va ); va_end( va ); } /* Keep the mailbox driver flag definitions in sync: */ /* grep for MAILBOX_DRIVER_FLAG */ /* The order is according to alphabetical maildir flag sort */ static const char Flags[] = { 'D', 'F', 'P', 'R', 'S', 'T' }; static uchar parse_flags( const char *buf ) { uint i, d; uchar flags; for (flags = i = d = 0; i < as(Flags); i++) if (buf[d] == Flags[i]) { flags |= (1 << i); d++; } return flags; } static uint make_flags( uchar flags, char *buf ) { uint i, d; for (i = d = 0; i < as(Flags); i++) if (flags & (1 << i)) buf[d++] = Flags[i]; buf[d] = 0; return d; } // This is the (mostly) persistent status of the sync record. // Most of these bits are actually mutually exclusive. It is a // bitfield to allow for easy testing for multiple states. #define S_EXPIRE (1<<0) // the entry is being expired (near side message removal scheduled) #define S_EXPIRED (1<<1) // the entry is expired (near side message removal confirmed) #define S_PENDING (1<<2) // the entry is new and awaits propagation (possibly a retry) #define S_DUMMY(fn) (1<<(3+(fn))) // f/n message is only a placeholder #define S_SKIPPED (1<<5) // pre-1.4 legacy: the entry was not propagated (message is too big) #define S_DEAD (1<<7) // ephemeral: the entry was killed and should be ignored // Ephemeral working set. #define W_NEXPIRE (1<<0) // temporary: new expiration state #define W_DELETE (1<<1) // ephemeral: flags propagation is a deletion #define W_DEL(fn) (1<<(2+(fn))) // ephemeral: f/n message would be subject to expunge #define W_UPGRADE (1<<4) // ephemeral: upgrading placeholder, do not apply MaxSize #define W_PURGE (1<<5) // ephemeral: placeholder is being nuked typedef struct sync_rec { struct sync_rec *next; /* string_list_t *keywords; */ uint uid[2]; message_t *msg[2]; uchar status, wstate, flags, pflags, aflags[2], dflags[2]; char tuid[TUIDL]; } sync_rec_t; typedef struct { int t[2]; void (*cb)( int sts, void *aux ), *aux; char *dname, *jname, *nname, *lname, *box_name[2]; FILE *jfp, *nfp; sync_rec_t *srecs, **srecadd; channel_conf_t *chan; store_t *ctx[2]; driver_t *drv[2]; const char *orig_name[2]; message_t *msgs[2], *new_msgs[2]; uint_array_alloc_t trashed_msgs[2]; int state[2], lfd, ret, existing, replayed; uint ref_count, nsrecs, opts[2]; uint new_pending[2], flags_pending[2], trash_pending[2]; uint maxuid[2]; // highest UID that was already propagated uint oldmaxuid[2]; // highest UID that was already propagated before this run uint uidval[2]; // UID validity value uint newuidval[2]; // UID validity obtained from driver uint finduid[2]; // TUID lookup makes sense only for UIDs >= this uint maxxfuid; // highest expired UID on far side uint oldmaxxfuid; // highest expired UID on far side before this run uchar good_flags[2], bad_flags[2]; } sync_vars_t; static void sync_ref( sync_vars_t *svars ) { ++svars->ref_count; } static void sync_deref( sync_vars_t *svars ); static int check_cancel( sync_vars_t *svars ); #define AUX &svars->t[t] #define INV_AUX &svars->t[1-t] #define DECL_SVARS \ int t; \ sync_vars_t *svars #define INIT_SVARS(aux) \ t = *(int *)aux; \ svars = (sync_vars_t *)(((char *)(&((int *)aux)[-t])) - offsetof(sync_vars_t, t)) #define DECL_INIT_SVARS(aux) \ int t = *(int *)aux; \ sync_vars_t *svars = (sync_vars_t *)(((char *)(&((int *)aux)[-t])) - offsetof(sync_vars_t, t)) /* operation dependencies: select(x): - load(x): select(x) new(F), new(N), flags(F), flags(N): load(F) & load(N) find_new(x): new(x) trash(x): flags(x) close(x): trash(x) & find_new(x) & new(!x) // with expunge cleanup: close(F) & close(N) */ #define ST_LOADED (1<<0) #define ST_FIND_OLD (1<<1) #define ST_SENT_NEW (1<<2) #define ST_FIND_NEW (1<<3) #define ST_FOUND_NEW (1<<4) #define ST_SENT_FLAGS (1<<5) #define ST_SENT_TRASH (1<<6) #define ST_CLOSED (1<<7) #define ST_SENT_CANCEL (1<<8) #define ST_CANCELED (1<<9) #define ST_SELECTED (1<<10) #define ST_DID_EXPUNGE (1<<11) #define ST_CLOSING (1<<12) #define ST_CONFIRMED (1<<13) #define ST_PRESENT (1<<14) #define ST_SENDING_NEW (1<<15) static void create_state( sync_vars_t *svars ) { if (!(svars->nfp = fopen( svars->nname, "w" ))) { sys_error( "Error: cannot create new sync state %s", svars->nname ); exit( 1 ); } } static void ATTR_PRINTFLIKE(2, 3) jFprintf( sync_vars_t *svars, const char *msg, ... ) { va_list va; if (JLimit && !--JLimit) exit( 101 ); if (!svars->jfp) { create_state( svars ); if (!(svars->jfp = fopen( svars->jname, svars->replayed ? "a" : "w" ))) { sys_error( "Error: cannot create journal %s", svars->jname ); exit( 1 ); } setlinebuf( svars->jfp ); if (!svars->replayed) Fprintf( svars->jfp, JOURNAL_VERSION "\n" ); } va_start( va, msg ); vFprintf( svars->jfp, msg, va ); va_end( va ); if (JLimit && !--JLimit) exit( 100 ); } #define JLOG_(log_fmt, log_args, dbg_fmt, ...) \ do { \ debug( "-> log: " log_fmt " (" dbg_fmt ")\n", __VA_ARGS__ ); \ jFprintf( svars, log_fmt "\n", deparen(log_args) ); \ } while (0) #define JLOG3(log_fmt, log_args, dbg_fmt) \ JLOG_(log_fmt, log_args, dbg_fmt, deparen(log_args)) #define JLOG4(log_fmt, log_args, dbg_fmt, dbg_args) \ JLOG_(log_fmt, log_args, dbg_fmt, deparen(log_args), deparen(dbg_args)) #define JLOG_SEL(_1, _2, _3, _4, x, ...) x #define JLOG(...) JLOG_SEL(__VA_ARGS__, JLOG4, JLOG3, NO_JLOG2, NO_JLOG1)(__VA_ARGS__) static void assign_uid( sync_vars_t *svars, sync_rec_t *srec, int t, uint uid ) { srec->uid[t] = uid; if (uid == svars->maxuid[t] + 1) svars->maxuid[t] = uid; srec->status &= ~S_PENDING; srec->wstate &= ~W_UPGRADE; srec->tuid[0] = 0; } #define ASSIGN_UID(srec, t, nuid, ...) \ do { \ JLOG( "%c %u %u %u", ("<>"[t], srec->uid[F], srec->uid[N], nuid), __VA_ARGS__ ); \ assign_uid( svars, srec, t, nuid ); \ } while (0) static void match_tuids( sync_vars_t *svars, int t, message_t *msgs ) { sync_rec_t *srec; message_t *tmsg, *ntmsg = NULL; const char *diag; int num_lost = 0; for (srec = svars->srecs; srec; srec = srec->next) { if (srec->status & S_DEAD) continue; if (!srec->uid[t] && srec->tuid[0]) { debug( "pair(%u,%u) TUID %." stringify(TUIDL) "s\n", srec->uid[F], srec->uid[N], srec->tuid ); for (tmsg = ntmsg; tmsg; tmsg = tmsg->next) { if (tmsg->status & M_DEAD) continue; if (tmsg->tuid[0] && !memcmp( tmsg->tuid, srec->tuid, TUIDL )) { diag = (tmsg == ntmsg) ? "adjacently" : "after gap"; goto mfound; } } for (tmsg = msgs; tmsg != ntmsg; tmsg = tmsg->next) { if (tmsg->status & M_DEAD) continue; if (tmsg->tuid[0] && !memcmp( tmsg->tuid, srec->tuid, TUIDL )) { diag = "after reset"; goto mfound; } } JLOG( "& %u %u", (srec->uid[F], srec->uid[N]), "TUID lost" ); // Note: status remains S_PENDING. srec->tuid[0] = 0; num_lost++; continue; mfound: tmsg->srec = srec; srec->msg[t] = tmsg; ntmsg = tmsg->next; ASSIGN_UID( srec, t, tmsg->uid, "TUID matched %s", diag ); } } if (num_lost) warn( "Warning: lost track of %d %sed message(s)\n", num_lost, str_hl[t] ); } static uchar sanitize_flags( uchar tflags, sync_vars_t *svars, int t ) { if (!(DFlags & QUIET)) { // We complain only once per flag per store - even though _theoretically_ // each mailbox can support different flags according to the IMAP spec. uchar bflags = tflags & ~(svars->good_flags[t] | svars->bad_flags[t]); if (bflags) { char bfbuf[16]; make_flags( bflags, bfbuf ); notice( "Notice: %s store does not support flag(s) '%s'; not propagating.\n", str_fn[t], bfbuf ); svars->bad_flags[t] |= bflags; } } return tflags & svars->good_flags[t]; } typedef struct copy_vars { void (*cb)( int sts, uint uid, struct copy_vars *vars ); void *aux; sync_rec_t *srec; /* also ->tuid */ message_t *msg; msg_data_t data; int minimal; } copy_vars_t; static void msg_fetched( int sts, void *aux ); static void copy_msg( copy_vars_t *vars ) { DECL_INIT_SVARS(vars->aux); t ^= 1; vars->data.flags = vars->msg->flags; vars->data.date = svars->chan->use_internal_date ? -1 : 0; svars->drv[t]->fetch_msg( svars->ctx[t], vars->msg, &vars->data, vars->minimal, msg_fetched, vars ); } static void msg_stored( int sts, uint uid, void *aux ); static void copy_msg_bytes( char **out_ptr, const char *in_buf, uint *in_idx, uint in_len, int in_cr, int out_cr ) { char *out = *out_ptr; uint idx = *in_idx; if (out_cr != in_cr) { char c; if (out_cr) { for (; idx < in_len; idx++) { if ((c = in_buf[idx]) != '\r') { if (c == '\n') *out++ = '\r'; *out++ = c; } } } else { for (; idx < in_len; idx++) { if ((c = in_buf[idx]) != '\r') *out++ = c; } } } else { memcpy( out, in_buf + idx, in_len - idx ); out += in_len - idx; idx = in_len; } *out_ptr = out; *in_idx = idx; } static int copy_msg_convert( int in_cr, int out_cr, copy_vars_t *vars, int t ) { char *in_buf = vars->data.data; uint in_len = vars->data.len; uint idx = 0, sbreak = 0, ebreak = 0, break2 = UINT_MAX; uint lines = 0, hdr_crs = 0, bdy_crs = 0, app_cr = 0, extra = 0; uint add_subj = 0; if (vars->srec) { nloop: ; uint start = idx; uint line_crs = 0; while (idx < in_len) { char c = in_buf[idx++]; if (c == '\r') { line_crs++; } else if (c == '\n') { if (!ebreak && starts_with_upper( in_buf + start, (int)(in_len - start), "X-TUID: ", 8 )) { extra = (sbreak = start) - (ebreak = idx); if (!vars->minimal) goto oke; } else { if (break2 == UINT_MAX && vars->minimal && starts_with_upper( in_buf + start, (int)(in_len - start), "SUBJECT:", 8 )) { break2 = start + 8; if (break2 < in_len && in_buf[break2] == ' ') break2++; } lines++; hdr_crs += line_crs; } if (idx - line_crs - 1 == start) { if (!ebreak) sbreak = ebreak = start; if (vars->minimal) { in_len = idx; if (break2 == UINT_MAX) { break2 = start; add_subj = 1; } } goto oke; } goto nloop; } } warn( "Warning: message %u from %s has incomplete header; skipping.\n", vars->msg->uid, str_fn[1-t] ); free( in_buf ); return 0; oke: app_cr = out_cr && (!in_cr || hdr_crs); extra += 8 + TUIDL + app_cr + 1; } if (out_cr != in_cr) { for (; idx < in_len; idx++) { char c = in_buf[idx]; if (c == '\r') bdy_crs++; else if (c == '\n') lines++; } extra -= hdr_crs + bdy_crs; if (out_cr) extra += lines; } uint dummy_msg_len = 0; char dummy_msg_buf[180]; static const char dummy_pfx[] = "[placeholder] "; static const char dummy_subj[] = "Subject: [placeholder] (No Subject)"; static const char dummy_msg[] = "Having a size of %s, this message is over the MaxSize limit.%s" "Flag it and sync again (Sync mode ReNew) to fetch its real contents.%s"; if (vars->minimal) { char sz[32]; if (vars->msg->size < 1024000) sprintf( sz, "%dKiB", (int)(vars->msg->size >> 10) ); else sprintf( sz, "%.1fMiB", vars->msg->size / 1048576. ); const char *nl = app_cr ? "\r\n" : "\n"; dummy_msg_len = (uint)sprintf( dummy_msg_buf, dummy_msg, sz, nl, nl ); extra += dummy_msg_len; extra += add_subj ? strlen(dummy_subj) + app_cr + 1 : strlen(dummy_pfx); } vars->data.len = in_len + extra; if (vars->data.len > INT_MAX) { warn( "Warning: message %u from %s is too big after conversion; skipping.\n", vars->msg->uid, str_fn[1-t] ); free( in_buf ); return 0; } char *out_buf = vars->data.data = nfmalloc( vars->data.len ); idx = 0; if (vars->srec) { if (break2 < sbreak) { copy_msg_bytes( &out_buf, in_buf, &idx, break2, in_cr, out_cr ); memcpy( out_buf, dummy_pfx, strlen(dummy_pfx) ); out_buf += strlen(dummy_pfx); } copy_msg_bytes( &out_buf, in_buf, &idx, sbreak, in_cr, out_cr ); memcpy( out_buf, "X-TUID: ", 8 ); out_buf += 8; memcpy( out_buf, vars->srec->tuid, TUIDL ); out_buf += TUIDL; if (app_cr) *out_buf++ = '\r'; *out_buf++ = '\n'; idx = ebreak; if (break2 != UINT_MAX && break2 >= sbreak) { copy_msg_bytes( &out_buf, in_buf, &idx, break2, in_cr, out_cr ); if (!add_subj) { memcpy( out_buf, dummy_pfx, strlen(dummy_pfx) ); out_buf += strlen(dummy_pfx); } else { memcpy( out_buf, dummy_subj, strlen(dummy_subj) ); out_buf += strlen(dummy_subj); if (app_cr) *out_buf++ = '\r'; *out_buf++ = '\n'; } } } copy_msg_bytes( &out_buf, in_buf, &idx, in_len, in_cr, out_cr ); if (vars->minimal) memcpy( out_buf, dummy_msg_buf, dummy_msg_len ); free( in_buf ); return 1; } static void msg_fetched( int sts, void *aux ) { copy_vars_t *vars = (copy_vars_t *)aux; DECL_SVARS; int scr, tcr; switch (sts) { case DRV_OK: INIT_SVARS(vars->aux); if (check_cancel( svars )) { free( vars->data.data ); vars->cb( SYNC_CANCELED, 0, vars ); return; } vars->msg->flags = vars->data.flags = sanitize_flags( vars->data.flags, svars, t ); scr = (svars->drv[1-t]->get_caps( svars->ctx[1-t] ) / DRV_CRLF) & 1; tcr = (svars->drv[t]->get_caps( svars->ctx[t] ) / DRV_CRLF) & 1; if (vars->srec || scr != tcr) { if (!copy_msg_convert( scr, tcr, vars, t )) { vars->cb( SYNC_NOGOOD, 0, vars ); return; } } svars->drv[t]->store_msg( svars->ctx[t], &vars->data, !vars->srec, msg_stored, vars ); break; case DRV_CANCELED: vars->cb( SYNC_CANCELED, 0, vars ); break; case DRV_MSG_BAD: vars->cb( SYNC_NOGOOD, 0, vars ); break; default: vars->cb( SYNC_FAIL, 0, vars ); break; } } static void msg_stored( int sts, uint uid, void *aux ) { copy_vars_t *vars = (copy_vars_t *)aux; DECL_SVARS; switch (sts) { case DRV_OK: vars->cb( SYNC_OK, uid, vars ); break; case DRV_CANCELED: vars->cb( SYNC_CANCELED, 0, vars ); break; case DRV_MSG_BAD: INIT_SVARS(vars->aux); (void)svars; warn( "Warning: %s refuses to store message %u from %s.\n", str_fn[t], vars->msg->uid, str_fn[1-t] ); vars->cb( SYNC_NOGOOD, 0, vars ); break; default: vars->cb( SYNC_FAIL, 0, vars ); break; } } static void sync_bail( sync_vars_t *svars ); static void sync_bail2( sync_vars_t *svars ); static void sync_bail3( sync_vars_t *svars ); static void cancel_done( void *aux ); static void cancel_sync( sync_vars_t *svars ) { int t; for (t = 0; t < 2; t++) { int other_state = svars->state[1-t]; if (svars->ret & SYNC_BAD(t)) { cancel_done( AUX ); } else if (!(svars->state[t] & ST_SENT_CANCEL)) { /* ignore subsequent failures from in-flight commands */ svars->state[t] |= ST_SENT_CANCEL; svars->drv[t]->cancel_cmds( svars->ctx[t], cancel_done, AUX ); } if (other_state & ST_CANCELED) break; } } static void cancel_done( void *aux ) { DECL_INIT_SVARS(aux); svars->state[t] |= ST_CANCELED; if (svars->state[1-t] & ST_CANCELED) { if (svars->nfp) { Fclose( svars->nfp, 0 ); Fclose( svars->jfp, 0 ); } sync_bail( svars ); } } static void store_bad( void *aux ) { DECL_INIT_SVARS(aux); svars->drv[t]->cancel_store( svars->ctx[t] ); svars->ret |= SYNC_BAD(t); cancel_sync( svars ); } static int check_cancel( sync_vars_t *svars ) { return (svars->state[F] | svars->state[N]) & (ST_SENT_CANCEL | ST_CANCELED); } static int check_ret( int sts, void *aux ) { DECL_SVARS; if (sts == DRV_CANCELED) return 1; INIT_SVARS(aux); if (sts == DRV_BOX_BAD) { svars->ret |= SYNC_FAIL; cancel_sync( svars ); return 1; } return check_cancel( svars ); } #define SVARS_CHECK_RET \ DECL_SVARS; \ if (check_ret( sts, aux )) \ return; \ INIT_SVARS(aux) #define SVARS_CHECK_RET_VARS(type) \ type *vars = (type *)aux; \ DECL_SVARS; \ if (check_ret( sts, vars->aux )) { \ free( vars ); \ return; \ } \ INIT_SVARS(vars->aux) #define SVARS_CHECK_CANCEL_RET \ DECL_SVARS; \ if (sts == SYNC_CANCELED) { \ free( vars ); \ return; \ } \ INIT_SVARS(vars->aux) static char * clean_strdup( const char *s ) { char *cs; uint i; cs = nfstrdup( s ); for (i = 0; cs[i]; i++) if (cs[i] == '/') cs[i] = '!'; return cs; } static sync_rec_t * upgrade_srec( sync_vars_t *svars, sync_rec_t *srec ) { // Create an entry and append it to the current one. sync_rec_t *nsrec = nfcalloc( sizeof(*nsrec) ); nsrec->next = srec->next; srec->next = nsrec; if (svars->srecadd == &srec->next) svars->srecadd = &nsrec->next; // Move the placeholder to the new entry. int t = (srec->status & S_DUMMY(F)) ? F : N; nsrec->uid[t] = srec->uid[t]; srec->uid[t] = 0; if (srec->msg[t]) { // NULL during journal replay; is assigned later. nsrec->msg[t] = srec->msg[t]; nsrec->msg[t]->srec = nsrec; srec->msg[t] = NULL; } // Mark the original entry for upgrade. srec->status = (srec->status & ~(S_DUMMY(F)|S_DUMMY(N))) | S_PENDING; srec->wstate |= W_UPGRADE; // Mark the placeholder for nuking. nsrec->wstate = W_PURGE; nsrec->aflags[t] = F_DELETED; return nsrec; } static int prepare_state( sync_vars_t *svars ) { char *s, *cmname, *csname; channel_conf_t *chan; chan = svars->chan; if (!strcmp( chan->sync_state ? chan->sync_state : global_conf.sync_state, "*" )) { const char *path = svars->drv[N]->get_box_path( svars->ctx[N] ); if (!path) { error( "Error: store '%s' does not support in-box sync state\n", chan->stores[N]->name ); return 0; } nfasprintf( &svars->dname, "%s/." EXE "state", path ); } else { csname = clean_strdup( svars->box_name[N] ); if (chan->sync_state) nfasprintf( &svars->dname, "%s%s", chan->sync_state, csname ); else { char c = FieldDelimiter; cmname = clean_strdup( svars->box_name[F] ); nfasprintf( &svars->dname, "%s%c%s%c%s_%c%s%c%s", global_conf.sync_state, c, chan->stores[F]->name, c, cmname, c, chan->stores[N]->name, c, csname ); free( cmname ); } free( csname ); if (!(s = strrchr( svars->dname, '/' ))) { error( "Error: invalid SyncState location '%s'\n", svars->dname ); return 0; } *s = 0; if (mkdir( svars->dname, 0700 ) && errno != EEXIST) { sys_error( "Error: cannot create SyncState directory '%s'", svars->dname ); return 0; } *s = '/'; } nfasprintf( &svars->jname, "%s.journal", svars->dname ); nfasprintf( &svars->nname, "%s.new", svars->dname ); nfasprintf( &svars->lname, "%s.lock", svars->dname ); return 1; } static int lock_state( sync_vars_t *svars ) { struct flock lck; if (svars->lfd >= 0) return 1; memset( &lck, 0, sizeof(lck) ); #if SEEK_SET != 0 lck.l_whence = SEEK_SET; #endif #if F_WRLCK != 0 lck.l_type = F_WRLCK; #endif if ((svars->lfd = open( svars->lname, O_WRONLY|O_CREAT, 0666 )) < 0) { sys_error( "Error: cannot create lock file %s", svars->lname ); return 0; } if (fcntl( svars->lfd, F_SETLK, &lck )) { error( "Error: channel :%s:%s-:%s:%s is locked\n", svars->chan->stores[F]->name, svars->orig_name[F], svars->chan->stores[N]->name, svars->orig_name[N] ); close( svars->lfd ); svars->lfd = -1; return 0; } return 1; } static void save_state( sync_vars_t *svars ) { sync_rec_t *srec; char fbuf[16]; /* enlarge when support for keywords is added */ // If no change was made, the state is also unmodified. if (!svars->jfp && !svars->replayed) return; if (!svars->nfp) create_state( svars ); Fprintf( svars->nfp, "FarUidValidity %u\nNearUidValidity %u\nMaxPulledUid %u\nMaxPushedUid %u\n", svars->uidval[F], svars->uidval[N], svars->maxuid[F], svars->maxuid[N] ); if (svars->maxxfuid) Fprintf( svars->nfp, "MaxExpiredFarUid %u\n", svars->maxxfuid ); Fprintf( svars->nfp, "\n" ); for (srec = svars->srecs; srec; srec = srec->next) { if (srec->status & S_DEAD) continue; make_flags( srec->flags, fbuf ); Fprintf( svars->nfp, "%u %u %s%s%s\n", srec->uid[F], srec->uid[N], (srec->status & S_DUMMY(F)) ? "<" : (srec->status & S_DUMMY(N)) ? ">" : "", (srec->status & S_SKIPPED) ? "^" : (srec->status & S_EXPIRED) ? "~" : "", fbuf ); } Fclose( svars->nfp, 1 ); if (svars->jfp) Fclose( svars->jfp, 0 ); if (!(DFlags & KEEPJOURNAL)) { /* order is important! */ if (rename( svars->nname, svars->dname )) warn( "Warning: cannot commit sync state %s\n", svars->dname ); else if (unlink( svars->jname )) warn( "Warning: cannot delete journal %s\n", svars->jname ); } } static int load_state( sync_vars_t *svars ) { sync_rec_t *srec, *nsrec; char *s; FILE *jfp; uint ll; uint maxxnuid = 0; char c; struct stat st; char fbuf[16]; /* enlarge when support for keywords is added */ char buf[128], buf1[64], buf2[64]; if ((jfp = fopen( svars->dname, "r" ))) { if (!lock_state( svars )) goto jbail; debug( "reading sync state %s ...\n", svars->dname ); int line = 0; while (fgets( buf, sizeof(buf), jfp )) { line++; if (!(ll = strlen( buf )) || buf[ll - 1] != '\n') { error( "Error: incomplete sync state header entry at %s:%d\n", svars->dname, line ); jbail: fclose( jfp ); return 0; } if (ll == 1) goto gothdr; if (line == 1 && isdigit( buf[0] )) { // Pre-1.1 legacy if (sscanf( buf, "%63s %63s", buf1, buf2 ) != 2 || sscanf( buf1, "%u:%u", &svars->uidval[F], &svars->maxuid[F] ) < 2 || sscanf( buf2, "%u:%u:%u", &svars->uidval[N], &maxxnuid, &svars->maxuid[N] ) < 3) { error( "Error: invalid sync state header in %s\n", svars->dname ); goto jbail; } goto gothdr; } uint uid; if (sscanf( buf, "%63s %u", buf1, &uid ) != 2) { error( "Error: malformed sync state header entry at %s:%d\n", svars->dname, line ); goto jbail; } if (!strcmp( buf1, "FarUidValidity" ) || !strcmp( buf1, "MasterUidValidity" ) /* Pre-1.4 legacy */) svars->uidval[F] = uid; else if (!strcmp( buf1, "NearUidValidity" ) || !strcmp( buf1, "SlaveUidValidity" ) /* Pre-1.4 legacy */) svars->uidval[N] = uid; else if (!strcmp( buf1, "MaxPulledUid" )) svars->maxuid[F] = uid; else if (!strcmp( buf1, "MaxPushedUid" )) svars->maxuid[N] = uid; else if (!strcmp( buf1, "MaxExpiredFarUid" ) || !strcmp( buf1, "MaxExpiredMasterUid" ) /* Pre-1.4 legacy */) svars->maxxfuid = uid; else if (!strcmp( buf1, "MaxExpiredSlaveUid" )) // Pre-1.3 legacy maxxnuid = uid; else { error( "Error: unrecognized sync state header entry at %s:%d\n", svars->dname, line ); goto jbail; } } error( "Error: unterminated sync state header in %s\n", svars->dname ); goto jbail; gothdr: while (fgets( buf, sizeof(buf), jfp )) { line++; if (!(ll = strlen( buf )) || buf[--ll] != '\n') { error( "Error: incomplete sync state entry at %s:%d\n", svars->dname, line ); goto jbail; } buf[ll] = 0; fbuf[0] = 0; uint t1, t2; if (sscanf( buf, "%u %u %15s", &t1, &t2, fbuf ) < 2) { error( "Error: invalid sync state entry at %s:%d\n", svars->dname, line ); goto jbail; } srec = nfcalloc( sizeof(*srec) ); srec->uid[F] = t1; srec->uid[N] = t2; s = fbuf; if (*s == '<') { s++; srec->status = S_DUMMY(F); } else if (*s == '>') { s++; srec->status = S_DUMMY(N); } if (*s == '^') { // Pre-1.4 legacy s++; srec->status = S_SKIPPED; } else if (*s == '~' || *s == 'X' /* Pre-1.3 legacy */) { s++; srec->status = S_EXPIRE | S_EXPIRED; } else if (srec->uid[F] == (uint)-1) { // Pre-1.3 legacy srec->uid[F] = 0; srec->status = S_SKIPPED; } else if (srec->uid[N] == (uint)-1) { srec->uid[N] = 0; srec->status = S_SKIPPED; } srec->flags = parse_flags( s ); debug( " entry (%u,%u,%u,%s%s)\n", srec->uid[F], srec->uid[N], srec->flags, (srec->status & S_SKIPPED) ? "SKIP" : (srec->status & S_EXPIRED) ? "XPIRE" : "", (srec->status & S_DUMMY(F)) ? ",F-DUMMY" : (srec->status & S_DUMMY(N)) ? ",N-DUMMY" : "" ); *svars->srecadd = srec; svars->srecadd = &srec->next; svars->nsrecs++; } fclose( jfp ); svars->existing = 1; } else { if (errno != ENOENT) { sys_error( "Error: cannot read sync state %s", svars->dname ); return 0; } svars->existing = 0; } // This is legacy support for pre-1.3 sync states. if (maxxnuid) { uint minwuid = UINT_MAX; for (srec = svars->srecs; srec; srec = srec->next) { if ((srec->status & (S_DEAD | S_SKIPPED | S_PENDING)) || !srec->uid[F]) continue; if (srec->status & S_EXPIRED) { if (!srec->uid[N]) { // The expired message was already gone. continue; } // The expired message was not expunged yet, so re-examine it. // This will happen en masse, so just extend the bulk fetch. } else { if (srec->uid[N] && maxxnuid >= srec->uid[N]) { // The non-expired message is in the generally expired range, // so don't make it contribute to the bulk fetch. continue; } // Usual non-expired message. } if (minwuid > srec->uid[F]) minwuid = srec->uid[F]; } svars->maxxfuid = minwuid - 1; } int line = 0; if ((jfp = fopen( svars->jname, "r" ))) { if (!lock_state( svars )) goto jbail; if (!stat( svars->nname, &st ) && fgets( buf, sizeof(buf), jfp )) { debug( "recovering journal ...\n" ); if (!(ll = strlen( buf )) || buf[--ll] != '\n') { error( "Error: incomplete journal header in %s\n", svars->jname ); goto jbail; } buf[ll] = 0; if (!equals( buf, (int)ll, JOURNAL_VERSION, strlen(JOURNAL_VERSION) )) { error( "Error: incompatible journal version " "(got %s, expected " JOURNAL_VERSION ")\n", buf ); goto jbail; } srec = NULL; line = 1; while (fgets( buf, sizeof(buf), jfp )) { line++; if (!(ll = strlen( buf )) || buf[--ll] != '\n') { error( "Error: incomplete journal entry at %s:%d\n", svars->jname, line ); goto jbail; } buf[ll] = 0; int tn; uint t1, t2, t3, t4; if ((c = buf[0]) == '#' ? (tn = 0, (sscanf( buf + 2, "%u %u %n", &t1, &t2, &tn ) < 2) || !tn || (ll - (uint)tn != TUIDL + 2)) : c == '!' ? (sscanf( buf + 2, "%u", &t1 ) != 1) : c == 'N' || c == 'F' || c == 'T' || c == '+' || c == '&' || c == '-' || c == '=' || c == '_' || c == '|' ? (sscanf( buf + 2, "%u %u", &t1, &t2 ) != 2) : c != '^' ? (sscanf( buf + 2, "%u %u %u", &t1, &t2, &t3 ) != 3) : (sscanf( buf + 2, "%u %u %u %u", &t1, &t2, &t3, &t4 ) != 4)) { error( "Error: malformed journal entry at %s:%d\n", svars->jname, line ); goto jbail; } if (c == 'N') svars->maxuid[t1] = t2; else if (c == 'F') svars->finduid[t1] = t2; else if (c == 'T') *uint_array_append( &svars->trashed_msgs[t1] ) = t2; else if (c == '!') svars->maxxfuid = t1; else if (c == '|') { svars->uidval[F] = t1; svars->uidval[N] = t2; } else if (c == '+') { srec = nfcalloc( sizeof(*srec) ); srec->uid[F] = t1; srec->uid[N] = t2; debug( " new entry(%u,%u)\n", t1, t2 ); srec->status = S_PENDING; *svars->srecadd = srec; svars->srecadd = &srec->next; svars->nsrecs++; } else { for (nsrec = srec; srec; srec = srec->next) if (srec->uid[F] == t1 && srec->uid[N] == t2) goto syncfnd; for (srec = svars->srecs; srec != nsrec; srec = srec->next) if (srec->uid[F] == t1 && srec->uid[N] == t2) goto syncfnd; error( "Error: journal entry at %s:%d refers to non-existing sync state entry\n", svars->jname, line ); goto jbail; syncfnd: debugn( " entry(%u,%u,%u) ", srec->uid[F], srec->uid[N], srec->flags ); switch (c) { case '-': debug( "killed\n" ); srec->status = S_DEAD; break; case '=': debug( "aborted\n" ); if (svars->maxxfuid < srec->uid[F]) svars->maxxfuid = srec->uid[F]; srec->status = S_DEAD; break; case '#': memcpy( srec->tuid, buf + tn + 2, TUIDL ); debug( "TUID now %." stringify(TUIDL) "s\n", srec->tuid ); break; case '&': debug( "TUID %." stringify(TUIDL) "s lost\n", srec->tuid ); srec->tuid[0] = 0; break; case '<': debug( "far side now %u\n", t3 ); assign_uid( svars, srec, F, t3 ); break; case '>': debug( "near side now %u\n", t3 ); assign_uid( svars, srec, N, t3 ); break; case '*': debug( "flags now %u\n", t3 ); srec->flags = (uchar)t3; srec->aflags[F] = srec->aflags[N] = 0; srec->wstate &= ~W_PURGE; break; case '~': debug( "status now %#x\n", t3 ); srec->status = (uchar)t3; break; case '_': debug( "has placeholder now\n" ); srec->status = S_PENDING; // Pre-1.4 legacy only srec->status |= !srec->uid[F] ? S_DUMMY(F) : S_DUMMY(N); break; case '^': debug( "is being upgraded, flags %u, srec flags %u\n", t3, t4 ); srec->pflags = (uchar)t3; srec->flags = (uchar)t4; srec = upgrade_srec( svars, srec ); break; default: error( "Error: unrecognized journal entry at %s:%d\n", svars->jname, line ); goto jbail; } } } } fclose( jfp ); } else { if (errno != ENOENT) { sys_error( "Error: cannot read journal %s", svars->jname ); return 0; } } svars->replayed = line; return 1; } static void delete_state( sync_vars_t *svars ) { unlink( svars->nname ); unlink( svars->jname ); if (unlink( svars->dname ) || unlink( svars->lname )) { sys_error( "Error: channel %s: sync state cannot be deleted", svars->chan->name ); svars->ret = SYNC_FAIL; } } static void box_confirmed( int sts, uint uidvalidity, void *aux ); static void box_confirmed2( sync_vars_t *svars, int t ); static void box_deleted( int sts, void *aux ); static void box_created( int sts, void *aux ); static void box_opened( int sts, uint uidvalidity, void *aux ); static void box_opened2( sync_vars_t *svars, int t ); static void load_box( sync_vars_t *svars, int t, uint minwuid, uint_array_t mexcs ); void sync_boxes( store_t *ctx[], const char * const names[], int present[], channel_conf_t *chan, void (*cb)( int sts, void *aux ), void *aux ) { sync_vars_t *svars; int t; svars = nfcalloc( sizeof(*svars) ); svars->t[1] = 1; svars->ref_count = 1; svars->cb = cb; svars->aux = aux; svars->ctx[0] = ctx[0]; svars->ctx[1] = ctx[1]; svars->chan = chan; svars->lfd = -1; svars->uidval[0] = svars->uidval[1] = UIDVAL_BAD; svars->srecadd = &svars->srecs; for (t = 0; t < 2; t++) { svars->orig_name[t] = (!names[t] || (ctx[t]->conf->map_inbox && !strcmp( ctx[t]->conf->map_inbox, names[t] ))) ? "INBOX" : names[t]; if (!ctx[t]->conf->flat_delim[0]) { svars->box_name[t] = nfstrdup( svars->orig_name[t] ); } else if (map_name( svars->orig_name[t], &svars->box_name[t], 0, "/", ctx[t]->conf->flat_delim ) < 0) { error( "Error: canonical mailbox name '%s' contains flattened hierarchy delimiter\n", svars->orig_name[t] ); bail3: svars->ret = SYNC_FAIL; sync_bail3( svars ); return; } svars->drv[t] = ctx[t]->driver; svars->drv[t]->set_bad_callback( ctx[t], store_bad, AUX ); } /* Both boxes must be fully set up at this point, so that error exit paths * don't run into uninitialized variables. */ for (t = 0; t < 2; t++) { switch (svars->drv[t]->select_box( ctx[t], svars->box_name[t] )) { case DRV_STORE_BAD: store_bad( AUX ); return; case DRV_BOX_BAD: goto bail3; } } if (!prepare_state( svars )) { svars->ret = SYNC_FAIL; sync_bail2( svars ); return; } if (!load_state( svars )) { svars->ret = SYNC_FAIL; sync_bail( svars ); return; } sync_ref( svars ); for (t = 0; ; t++) { info( "Opening %s box %s...\n", str_fn[t], svars->orig_name[t] ); if (present[t] == BOX_ABSENT) box_confirmed2( svars, t ); else svars->drv[t]->open_box( ctx[t], box_confirmed, AUX ); if (t || check_cancel( svars )) break; } sync_deref( svars ); } static void box_confirmed( int sts, uint uidvalidity, void *aux ) { DECL_SVARS; if (sts == DRV_CANCELED) return; INIT_SVARS(aux); if (check_cancel( svars )) return; if (sts == DRV_OK) { svars->state[t] |= ST_PRESENT; svars->newuidval[t] = uidvalidity; } box_confirmed2( svars, t ); } static void box_confirmed2( sync_vars_t *svars, int t ) { svars->state[t] |= ST_CONFIRMED; if (!(svars->state[1-t] & ST_CONFIRMED)) return; sync_ref( svars ); for (t = 0; ; t++) { if (!(svars->state[t] & ST_PRESENT)) { if (!(svars->state[1-t] & ST_PRESENT)) { if (!svars->existing) { error( "Error: channel %s: both far side %s and near side %s cannot be opened.\n", svars->chan->name, svars->orig_name[F], svars->orig_name[N] ); bail: svars->ret = SYNC_FAIL; } else { /* This can legitimately happen if a deletion propagation was interrupted. * We have no place to record this transaction, so we just assume it. * Of course this bears the danger of clearing the state if both mailboxes * temorarily cannot be opened for some weird reason (while the stores can). */ delete_state( svars ); } done: sync_bail( svars ); break; } if (svars->existing) { if (!(svars->chan->ops[1-t] & OP_REMOVE)) { error( "Error: channel %s: %s box %s cannot be opened.\n", svars->chan->name, str_fn[t], svars->orig_name[t] ); goto bail; } if (svars->drv[1-t]->confirm_box_empty( svars->ctx[1-t] ) != DRV_OK) { warn( "Warning: channel %s: %s box %s cannot be opened and %s box %s is not empty.\n", svars->chan->name, str_fn[t], svars->orig_name[t], str_fn[1-t], svars->orig_name[1-t] ); goto done; } info( "Deleting %s box %s...\n", str_fn[1-t], svars->orig_name[1-t] ); svars->drv[1-t]->delete_box( svars->ctx[1-t], box_deleted, INV_AUX ); } else { if (!(svars->chan->ops[t] & OP_CREATE)) { box_opened( DRV_BOX_BAD, UIDVAL_BAD, AUX ); } else { info( "Creating %s box %s...\n", str_fn[t], svars->orig_name[t] ); svars->drv[t]->create_box( svars->ctx[t], box_created, AUX ); } } } else { box_opened2( svars, t ); } if (t || check_cancel( svars )) break; } sync_deref( svars ); } static void box_deleted( int sts, void *aux ) { DECL_SVARS; if (check_ret( sts, aux )) return; INIT_SVARS(aux); delete_state( svars ); svars->drv[t]->finish_delete_box( svars->ctx[t] ); sync_bail( svars ); } static void box_created( int sts, void *aux ) { DECL_SVARS; if (check_ret( sts, aux )) return; INIT_SVARS(aux); svars->drv[t]->open_box( svars->ctx[t], box_opened, AUX ); } static void box_opened( int sts, uint uidvalidity, void *aux ) { DECL_SVARS; if (sts == DRV_CANCELED) return; INIT_SVARS(aux); if (check_cancel( svars )) return; if (sts == DRV_BOX_BAD) { error( "Error: channel %s: %s box %s cannot be opened.\n", svars->chan->name, str_fn[t], svars->orig_name[t] ); svars->ret = SYNC_FAIL; sync_bail( svars ); } else { svars->newuidval[t] = uidvalidity; box_opened2( svars, t ); } } static void box_opened2( sync_vars_t *svars, int t ) { store_t *ctx[2]; channel_conf_t *chan; sync_rec_t *srec; uint_array_alloc_t mexcs; uint opts[2], fails, minwuid; svars->state[t] |= ST_SELECTED; if (!(svars->state[1-t] & ST_SELECTED)) return; ctx[0] = svars->ctx[0]; ctx[1] = svars->ctx[1]; chan = svars->chan; fails = 0; for (t = 0; t < 2; t++) if (svars->uidval[t] != UIDVAL_BAD && svars->uidval[t] != svars->newuidval[t]) fails++; // If only one side changed UIDVALIDITY, we will try to re-approve it further down. if (fails == 2) { error( "Error: channel %s: UIDVALIDITY of both far side %s and near side %s changed.\n", svars->chan->name, svars->orig_name[F], svars->orig_name[N]); bail: svars->ret = SYNC_FAIL; sync_bail( svars ); return; } if (!lock_state( svars )) goto bail; opts[F] = opts[N] = 0; if (fails) opts[F] = opts[N] = OPEN_OLD|OPEN_OLD_IDS; for (t = 0; t < 2; t++) { if (chan->ops[t] & (OP_DELETE|OP_FLAGS)) { opts[t] |= OPEN_SETFLAGS; opts[1-t] |= OPEN_OLD; if (chan->ops[t] & OP_FLAGS) opts[1-t] |= OPEN_FLAGS; } if (chan->ops[t] & (OP_NEW|OP_RENEW)) { opts[t] |= OPEN_APPEND; if (chan->ops[t] & OP_NEW) { opts[1-t] |= OPEN_NEW; if (chan->stores[t]->max_size != UINT_MAX) opts[1-t] |= OPEN_FLAGS|OPEN_NEW_SIZE; } if (chan->ops[t] & OP_RENEW) { opts[t] |= OPEN_OLD|OPEN_FLAGS|OPEN_SETFLAGS; opts[1-t] |= OPEN_OLD|OPEN_FLAGS; } if (chan->ops[t] & OP_EXPUNGE) // Don't propagate doomed msgs opts[1-t] |= OPEN_FLAGS; } if (chan->ops[t] & OP_EXPUNGE) { opts[t] |= OPEN_EXPUNGE; if (chan->stores[t]->trash) { if (!chan->stores[t]->trash_only_new) opts[t] |= OPEN_OLD; opts[t] |= OPEN_NEW|OPEN_FLAGS; } else if (chan->stores[1-t]->trash && chan->stores[1-t]->trash_remote_new) opts[t] |= OPEN_NEW|OPEN_FLAGS; } } if ((chan->ops[N] & (OP_NEW|OP_RENEW|OP_FLAGS)) && chan->max_messages) opts[N] |= OPEN_OLD|OPEN_NEW|OPEN_FLAGS; if (svars->replayed) for (srec = svars->srecs; srec; srec = srec->next) { if (srec->status & S_DEAD) continue; if (srec->tuid[0]) { if (!srec->uid[F]) opts[F] |= OPEN_NEW|OPEN_FIND, svars->state[F] |= ST_FIND_OLD; else if (!srec->uid[N]) opts[N] |= OPEN_NEW|OPEN_FIND, svars->state[N] |= ST_FIND_OLD; else warn( "Warning: sync record (%u,%u) has stray TUID. Ignoring.\n", srec->uid[F], srec->uid[N] ); } if (srec->wstate & W_PURGE) { t = srec->uid[F] ? F : N; opts[t] |= OPEN_SETFLAGS; } if (srec->wstate & W_UPGRADE) { t = !srec->uid[F] ? F : N; opts[t] |= OPEN_APPEND; opts[1-t] |= OPEN_OLD; } } svars->opts[F] = svars->drv[F]->prepare_load_box( ctx[F], opts[F] ); svars->opts[N] = svars->drv[N]->prepare_load_box( ctx[N], opts[N] ); ARRAY_INIT( &mexcs ); if (svars->opts[F] & OPEN_OLD) { if (chan->max_messages) { /* When messages have been expired on the near side, the far side fetch is split into * two ranges: The bulk fetch which corresponds with the most recent messages, and an * exception list of messages which would have been expired if they weren't important. */ debug( "preparing far side selection - max expired far uid is %u\n", svars->maxxfuid ); /* First, find out the lower bound for the bulk fetch. */ minwuid = svars->maxxfuid + 1; /* Next, calculate the exception fetch. */ for (srec = svars->srecs; srec; srec = srec->next) { if (srec->status & S_DEAD) continue; if (!srec->uid[F]) continue; // No message; other state is irrelevant if (srec->uid[F] >= minwuid) continue; // Message is in non-expired range if ((svars->opts[F] & OPEN_NEW) && srec->uid[F] >= svars->maxuid[F]) continue; // Message is in expired range, but new range overlaps that if (!srec->uid[N] && !(srec->status & S_PENDING)) continue; // Only actually paired up messages matter // The pair is alive, but outside the bulk range *uint_array_append( &mexcs ) = srec->uid[F]; } sort_uint_array( mexcs.array ); } else { minwuid = 1; } } else { minwuid = UINT_MAX; } sync_ref( svars ); load_box( svars, F, minwuid, mexcs.array ); if (!check_cancel( svars )) load_box( svars, N, (svars->opts[N] & OPEN_OLD) ? 1 : UINT_MAX, (uint_array_t){ NULL, 0 } ); sync_deref( svars ); } static uint get_seenuid( sync_vars_t *svars, int t ) { uint seenuid = 0; for (sync_rec_t *srec = svars->srecs; srec; srec = srec->next) if (!(srec->status & S_DEAD) && seenuid < srec->uid[t]) seenuid = srec->uid[t]; return seenuid; } static void box_loaded( int sts, message_t *msgs, int total_msgs, int recent_msgs, void *aux ); static void load_box( sync_vars_t *svars, int t, uint minwuid, uint_array_t mexcs ) { uint maxwuid = 0, pairuid = UINT_MAX; if (svars->opts[t] & OPEN_NEW) { if (minwuid > svars->maxuid[t] + 1) minwuid = svars->maxuid[t] + 1; maxwuid = UINT_MAX; if (svars->opts[t] & OPEN_OLD_IDS) // Implies OPEN_OLD pairuid = get_seenuid( svars, t ); } else if (svars->opts[t] & OPEN_OLD) { maxwuid = get_seenuid( svars, t ); } info( "Loading %s box...\n", str_fn[t] ); svars->drv[t]->load_box( svars->ctx[t], minwuid, maxwuid, svars->finduid[t], pairuid, svars->maxuid[t], mexcs, box_loaded, AUX ); } typedef struct { void *aux; sync_rec_t *srec; int aflags, dflags; } flag_vars_t; typedef struct { uint uid; sync_rec_t *srec; } sync_rec_map_t; static void flags_set( int sts, void *aux ); static void flags_set_p2( sync_vars_t *svars, sync_rec_t *srec, int t ); static void msgs_flags_set( sync_vars_t *svars, int t ); static void msg_copied( int sts, uint uid, copy_vars_t *vars ); static void msgs_copied( sync_vars_t *svars, int t ); static void box_loaded( int sts, message_t *msgs, int total_msgs, int recent_msgs, void *aux ) { DECL_SVARS; sync_rec_t *srec; sync_rec_map_t *srecmap; message_t *tmsg; flag_vars_t *fv; int no[2], del[2], alive, todel; uchar sflags, nflags, aflags, dflags; uint hashsz, idx; if (check_ret( sts, aux )) return; INIT_SVARS(aux); svars->state[t] |= ST_LOADED; svars->msgs[t] = msgs; info( "%s: %d messages, %d recent\n", str_fn[t], total_msgs, recent_msgs ); if (svars->state[t] & ST_FIND_OLD) { debug( "matching previously copied messages on %s\n", str_fn[t] ); match_tuids( svars, t, msgs ); } debug( "matching messages on %s against sync records\n", str_fn[t] ); hashsz = bucketsForSize( svars->nsrecs * 3 ); srecmap = nfcalloc( hashsz * sizeof(*srecmap) ); for (srec = svars->srecs; srec; srec = srec->next) { if (srec->status & S_DEAD) continue; uint uid = srec->uid[t]; if (!uid) continue; idx = (uint)(uid * 1103515245U) % hashsz; while (srecmap[idx].uid) if (++idx == hashsz) idx = 0; srecmap[idx].uid = uid; srecmap[idx].srec = srec; } for (tmsg = svars->msgs[t]; tmsg; tmsg = tmsg->next) { if (tmsg->srec) /* found by TUID */ continue; uint uid = tmsg->uid; idx = (uint)(uid * 1103515245U) % hashsz; while (srecmap[idx].uid) { if (srecmap[idx].uid == uid) { srec = srecmap[idx].srec; goto found; } if (++idx == hashsz) idx = 0; } continue; found: tmsg->srec = srec; srec->msg[t] = tmsg; } free( srecmap ); if (!(svars->state[1-t] & ST_LOADED)) return; for (t = 0; t < 2; t++) { if (svars->uidval[t] != UIDVAL_BAD && svars->uidval[t] != svars->newuidval[t]) { // This code checks whether the messages with known UIDs are actually the // same messages, as recognized by their Message-IDs. unsigned need = 0, got = 0; debug( "trying to re-approve uid validity of %s\n", str_fn[t] ); for (srec = svars->srecs; srec; srec = srec->next) { if (srec->status & S_DEAD) continue; need++; if (!srec->msg[t]) continue; // Message disappeared. // Present paired messages require re-validation. if (!srec->msg[t]->msgid) continue; // Messages without ID are useless for re-validation. if (!srec->msg[1-t]) continue; // Partner disappeared. if (!srec->msg[1-t]->msgid || strcmp( srec->msg[F]->msgid, srec->msg[N]->msgid )) { error( "Error: channel %s, %s box %s: UIDVALIDITY genuinely changed (at UID %u).\n", svars->chan->name, str_fn[t], svars->orig_name[t], srec->uid[t] ); uvchg: svars->ret |= SYNC_FAIL; cancel_sync( svars ); return; } got++; } // We encountered no messages that contradict the hypothesis that the // UIDVALIDITY change was spurious. // If we got enough messages confirming the hypothesis, we just accept it. // If there aren't quite enough messages, we check that at least 80% of // those previously present are still there and confirm the hypothesis; // this also covers the case of a box that was already empty. if (got < 20 && got * 5 < need * 4) { // Too few confirmed messages. This is very likely in the drafts folder. // A proper fallback would be fetching more headers (which potentially need // normalization) or the message body (which should be truncated for sanity) // and comparing. error( "Error: channel %s, %s box %s: Unable to recover from UIDVALIDITY change.\n", svars->chan->name, str_fn[t], svars->orig_name[t] ); goto uvchg; } notice( "Notice: channel %s, %s box %s: Recovered from change of UIDVALIDITY.\n", svars->chan->name, str_fn[t], svars->orig_name[t] ); svars->uidval[t] = UIDVAL_BAD; } } if (svars->uidval[F] == UIDVAL_BAD || svars->uidval[N] == UIDVAL_BAD) { svars->uidval[F] = svars->newuidval[F]; svars->uidval[N] = svars->newuidval[N]; JLOG( "| %u %u", (svars->uidval[F], svars->uidval[N]), "new UIDVALIDITYs" ); } svars->oldmaxuid[F] = svars->maxuid[F]; svars->oldmaxuid[N] = svars->maxuid[N]; svars->oldmaxxfuid = svars->maxxfuid; info( "Synchronizing...\n" ); for (t = 0; t < 2; t++) svars->good_flags[t] = (uchar)svars->drv[t]->get_supported_flags( svars->ctx[t] ); int any_new[2] = { 0, 0 }; debug( "synchronizing old entries\n" ); for (srec = svars->srecs; srec; srec = srec->next) { if (srec->status & S_DEAD) continue; debug( "pair (%u,%u)\n", srec->uid[F], srec->uid[N] ); assert( !srec->tuid[0] ); // no[] means that a message is known to be not there. no[F] = !srec->msg[F] && (svars->opts[F] & OPEN_OLD); no[N] = !srec->msg[N] && (svars->opts[N] & OPEN_OLD); if (no[F] && no[N]) { // It does not matter whether one side was already known to be missing // (never stored [skipped or failed] or expunged [possibly expired]) - // now both are missing, so the entry is superfluous. srec->status = S_DEAD; JLOG( "- %u %u", (srec->uid[F], srec->uid[N]), "both missing" ); } else { // del[] means that a message becomes known to have been expunged. del[F] = no[F] && srec->uid[F]; del[N] = no[N] && srec->uid[N]; for (t = 0; t < 2; t++) { if (srec->msg[t] && (srec->msg[t]->flags & F_DELETED)) srec->wstate |= W_DEL(t); if (del[t]) { // The target was newly expunged, so there is nothing to update. // The deletion is propagated in the opposite iteration. } else if (!srec->uid[t]) { // The target was never stored, or was previously expunged, so there // is nothing to update. // Note: the opposite UID must be valid, as otherwise the entry would // have been pruned already. } else if (del[1-t]) { // The source was newly expunged, so possibly propagate the deletion. // The target may be in an unknown state (not fetched). if ((t == F) && (srec->status & (S_EXPIRE|S_EXPIRED))) { /* Don't propagate deletion resulting from expiration. */ JLOG( "> %u %u 0", (srec->uid[F], srec->uid[N]), "near side expired, orphaning far side" ); srec->uid[N] = 0; } else { if (srec->msg[t] && (srec->msg[t]->status & M_FLAGS) && // Ignore deleted flag, as that's what we'll change ourselves ... (((srec->msg[t]->flags & ~F_DELETED) != (srec->flags & ~F_DELETED)) || // ... except for undeletion, as that's the opposite. (!(srec->msg[t]->flags & F_DELETED) && (srec->flags & F_DELETED)))) notice( "Notice: conflicting changes in (%u,%u)\n", srec->uid[F], srec->uid[N] ); if (svars->chan->ops[t] & OP_DELETE) { debug( " %sing delete\n", str_hl[t] ); srec->aflags[t] = F_DELETED; srec->wstate |= W_DELETE; } else { debug( " not %sing delete\n", str_hl[t] ); } } } else if (!srec->msg[1-t]) { // We have no source to work with, because it was never stored, // it was previously expunged, or we did not fetch it. debug( " no %s\n", str_fn[1-t] ); } else { // We have a source. The target may be in an unknown state. if (svars->chan->ops[t] & OP_FLAGS) { sflags = sanitize_flags( srec->msg[1-t]->flags, svars, t ); if ((t == F) && (srec->status & (S_EXPIRE|S_EXPIRED))) { /* Don't propagate deletion resulting from expiration. */ debug( " near side expiring\n" ); sflags &= ~F_DELETED; } if (srec->status & S_DUMMY(1-t)) { // For placeholders, don't propagate: // - Seen, because the real contents were obviously not seen yet // - Flagged, because it's just a request to upgrade sflags &= ~(F_SEEN|F_FLAGGED); } srec->aflags[t] = sflags & ~srec->flags; srec->dflags[t] = ~sflags & srec->flags; if ((DFlags & DEBUG_SYNC) && (srec->aflags[t] || srec->dflags[t])) { char afbuf[16], dfbuf[16]; /* enlarge when support for keywords is added */ make_flags( srec->aflags[t], afbuf ); make_flags( srec->dflags[t], dfbuf ); debug( " %sing flags: +%s -%s\n", str_hl[t], afbuf, dfbuf ); } } } } sync_rec_t *nsrec = srec; if (((srec->status & S_DUMMY(F)) && (svars->chan->ops[F] & OP_RENEW)) || ((srec->status & S_DUMMY(N)) && (svars->chan->ops[N] & OP_RENEW))) { // Flagging the message on either side causes an upgrade of the dummy. // We ignore flag resets, because that corner case is not worth it. ushort muflags = srec->msg[F] ? srec->msg[F]->flags : 0; ushort suflags = srec->msg[N] ? srec->msg[N]->flags : 0; if ((muflags | suflags) & F_FLAGGED) { t = (srec->status & S_DUMMY(F)) ? F : N; // We calculate the flags for the replicated message already now, // because after an interruption the dummy may be already gone. srec->pflags = ((srec->msg[t]->flags & ~(F_SEEN|F_FLAGGED)) | srec->aflags[t]) & ~srec->dflags[t]; // Consequently, the srec's flags are committed right away as well. srec->flags = (srec->flags | srec->aflags[t]) & ~srec->dflags[t]; JLOG( "^ %u %u %u %u", (srec->uid[F], srec->uid[N], srec->pflags, srec->flags), "upgrading placeholder" ); nsrec = upgrade_srec( svars, srec ); } } // This is separated, because the upgrade can come from the journal. if (srec->wstate & W_UPGRADE) { t = !srec->uid[F] ? F : N; tmsg = srec->msg[1-t]; if ((svars->chan->ops[t] & OP_EXPUNGE) && (srec->pflags & F_DELETED)) { JLOG( "- %u %u", (srec->uid[F], srec->uid[N]), "killing upgrade - would be expunged anyway" ); tmsg->srec = NULL; srec->status = S_DEAD; } else { // Pretend that the source message has the adjusted flags of the dummy. tmsg->flags = srec->pflags; tmsg->status = M_FLAGS; any_new[t] = 1; } } srec = nsrec; } } for (t = 0; t < 2; t++) { debug( "synchronizing new messages on %s\n", str_fn[1-t] ); for (tmsg = svars->msgs[1-t]; tmsg; tmsg = tmsg->next) { srec = tmsg->srec; if (srec) { if (srec->status & S_SKIPPED) { // Pre-1.4 legacy only: The message was skipped due to being too big. // We must have already seen the UID, but we might have been interrupted. if (svars->maxuid[1-t] < tmsg->uid) svars->maxuid[1-t] = tmsg->uid; if (!(svars->chan->ops[t] & OP_RENEW)) continue; srec->status = S_PENDING; // The message size was not queried, so this won't be dummified below. if (!(tmsg->flags & F_FLAGGED)) { srec->status |= S_DUMMY(t); JLOG( "_ %u %u", (srec->uid[F], srec->uid[N]), "placeholder only - was previously skipped" ); } else { JLOG( "~ %u %u %u", (srec->uid[F], srec->uid[N], srec->status), "was previously skipped" ); } } else { if (!(svars->chan->ops[t] & OP_NEW)) continue; // This catches messages: // - that are actually new // - whose propagation got interrupted // - whose propagation was completed, but not logged yet // - that aren't actually new, but a result of syncing, and the instant // maxuid upping was prevented by the presence of actually new messages if (svars->maxuid[1-t] < tmsg->uid) svars->maxuid[1-t] = tmsg->uid; if (!(srec->status & S_PENDING)) continue; // Nothing to do - the message is paired or expired // Propagation was scheduled, but we got interrupted debug( "unpropagated old message %u\n", tmsg->uid ); } if ((svars->chan->ops[t] & OP_EXPUNGE) && (tmsg->flags & F_DELETED)) { JLOG( "- %u %u", (srec->uid[F], srec->uid[N]), "killing - would be expunged anyway" ); tmsg->srec = NULL; srec->status = S_DEAD; continue; } } else { if (!(svars->chan->ops[t] & OP_NEW)) continue; if (tmsg->uid <= svars->maxuid[1-t]) { // The message should be already paired. It's not, so it was: // - previously paired, but the entry was expired and pruned => ignore // - attempted, but failed => ignore (the wisdom of this is debatable) // - ignored, as it would have been expunged anyway => ignore (even if undeleted) continue; } svars->maxuid[1-t] = tmsg->uid; debug( "new message %u\n", tmsg->uid ); if ((svars->chan->ops[t] & OP_EXPUNGE) && (tmsg->flags & F_DELETED)) { debug( "-> ignoring - would be expunged anyway\n" ); continue; } srec = nfcalloc( sizeof(*srec) ); *svars->srecadd = srec; svars->srecadd = &srec->next; svars->nsrecs++; srec->status = S_PENDING; srec->uid[1-t] = tmsg->uid; srec->msg[1-t] = tmsg; tmsg->srec = srec; JLOG( "+ %u %u", (srec->uid[F], srec->uid[N]), "fresh" ); } if (!(tmsg->flags & F_FLAGGED) && tmsg->size > svars->chan->stores[t]->max_size && !(srec->wstate & W_UPGRADE) && !(srec->status & (S_DUMMY(F)|S_DUMMY(N)))) { srec->status |= S_DUMMY(t); JLOG( "_ %u %u", (srec->uid[F], srec->uid[N]), "placeholder only - too big" ); } any_new[t] = 1; } } if ((svars->chan->ops[N] & (OP_NEW|OP_RENEW|OP_FLAGS)) && svars->chan->max_messages) { // Note: When this branch is entered, we have loaded all near side messages. /* Expire excess messages. Important (flagged, unread, or unpropagated) messages * older than the first not expired message are not counted towards the total. */ debug( "preparing message expiration\n" ); // Due to looping only over the far side, we completely ignore unpaired // near-side messages. This is correct, as we cannot expire them without // data loss anyway; consequently, we also don't count them. // Note that we also ignore near-side messages we're currently propagating, // which delays expiration of some messages by one cycle. Otherwise, we'd have // to sequence flag propagation after message propagation to avoid a race // with 3rd-party expunging, and that seems unreasonably expensive. alive = 0; for (tmsg = svars->msgs[F]; tmsg; tmsg = tmsg->next) { if (tmsg->status & M_DEAD) continue; // We ignore unpaired far-side messages, as there is obviously nothing // to expire in the first place. if (!(srec = tmsg->srec)) continue; if (!(srec->status & S_PENDING)) { if (!srec->msg[N]) continue; // Already expired or skipped. nflags = (srec->msg[N]->flags | srec->aflags[N]) & ~srec->dflags[N]; } else { nflags = tmsg->flags; } if (!(nflags & F_DELETED) || (srec->status & (S_EXPIRE|S_EXPIRED))) // The message is not deleted, or it is, but only due to being expired. alive++; } todel = alive - svars->chan->max_messages; debug( "%d alive messages, %d excess - expiring\n", alive, todel ); alive = 0; for (tmsg = svars->msgs[F]; tmsg; tmsg = tmsg->next) { if (tmsg->status & M_DEAD) continue; if (!(srec = tmsg->srec)) continue; if (!(srec->status & S_PENDING)) { if (!srec->msg[N]) continue; nflags = (srec->msg[N]->flags | srec->aflags[N]) & ~srec->dflags[N]; } else { nflags = tmsg->flags; } if (!(nflags & F_DELETED) || (srec->status & (S_EXPIRE|S_EXPIRED))) { if ((nflags & F_FLAGGED) || !((nflags & F_SEEN) || ((void)(todel > 0 && alive++), svars->chan->expire_unread > 0))) { // Important messages are always fetched/kept. debug( " pair(%u,%u) is important\n", srec->uid[F], srec->uid[N] ); todel--; } else if (todel > 0 || ((srec->status & (S_EXPIRE|S_EXPIRED)) == (S_EXPIRE|S_EXPIRED)) || ((srec->status & (S_EXPIRE|S_EXPIRED)) && (srec->msg[N]->flags & F_DELETED))) { /* The message is excess or was already (being) expired. */ srec->wstate |= W_NEXPIRE; debug( " pair(%u,%u) expired\n", srec->uid[F], srec->uid[N] ); if (svars->maxxfuid < srec->uid[F]) svars->maxxfuid = srec->uid[F]; todel--; } } } debug( "%d excess messages remain\n", todel ); if (svars->chan->expire_unread < 0 && alive * 2 > svars->chan->max_messages) { error( "%s: %d unread messages in excess of MaxMessages (%d).\n" "Please set ExpireUnread to decide outcome. Skipping mailbox.\n", svars->orig_name[N], alive, svars->chan->max_messages ); svars->ret |= SYNC_FAIL; cancel_sync( svars ); return; } for (srec = svars->srecs; srec; srec = srec->next) { if (srec->status & S_DEAD) continue; if (!(srec->status & S_PENDING)) { if (!srec->msg[N]) continue; uchar nex = (srec->wstate / W_NEXPIRE) & 1; if (nex != ((srec->status / S_EXPIRED) & 1)) { /* The record needs a state change ... */ if (nex != ((srec->status / S_EXPIRE) & 1)) { /* ... and we need to start a transaction. */ srec->status = (srec->status & ~S_EXPIRE) | (nex * S_EXPIRE); JLOG( "~ %u %u %u", (srec->uid[F], srec->uid[N], srec->status), "expire %u - begin", nex ); } else { /* ... but the "right" transaction is already pending. */ debug( "-> pair(%u,%u): expire %u (pending)\n", srec->uid[F], srec->uid[N], nex ); } } else { /* Note: the "wrong" transaction may be pending here, * e.g.: W_NEXPIRE = 0, S_EXPIRE = 1, S_EXPIRED = 0. */ } } else { if (srec->wstate & W_NEXPIRE) { JLOG( "= %u %u", (srec->uid[F], srec->uid[N]), "expire unborn" ); // If we have so many new messages that some of them are instantly expired, // but some are still propagated because they are important, we need to // ensure explicitly that the bulk fetch limit is upped. if (svars->maxxfuid < srec->uid[F]) svars->maxxfuid = srec->uid[F]; srec->msg[F]->srec = NULL; srec->status = S_DEAD; } } } } sync_ref( svars ); debug( "synchronizing flags\n" ); for (srec = svars->srecs; srec; srec = srec->next) { if (srec->status & S_DEAD) continue; for (t = 0; t < 2; t++) { if (!srec->uid[t]) continue; aflags = srec->aflags[t]; dflags = srec->dflags[t]; if (srec->wstate & (W_DELETE|W_PURGE)) { if (!aflags) { // This deletion propagation goes the other way round, or // this deletion of a dummy happens on the other side. continue; } if (!srec->msg[t] && (svars->opts[t] & OPEN_OLD)) { // The message disappeared. This can happen, because the wstate may // come from the journal, and things could have happened meanwhile. continue; } } else { /* The trigger is an expiration transaction being ongoing ... */ if ((t == N) && ((shifted_bit(srec->status, S_EXPIRE, S_EXPIRED) ^ srec->status) & S_EXPIRED)) { /* ... but the actual action derives from the wanted state. */ if (srec->wstate & W_NEXPIRE) aflags |= F_DELETED; else dflags |= F_DELETED; } } if ((svars->chan->ops[t] & OP_EXPUNGE) && (((srec->msg[t] ? srec->msg[t]->flags : 0) | aflags) & ~dflags & F_DELETED) && (!svars->ctx[t]->conf->trash || svars->ctx[t]->conf->trash_only_new)) { /* If the message is going to be expunged, don't propagate anything but the deletion. */ srec->aflags[t] &= F_DELETED; aflags &= F_DELETED; srec->dflags[t] = dflags = 0; } if (srec->msg[t] && (srec->msg[t]->status & M_FLAGS)) { /* If we know the target message's state, optimize away non-changes. */ aflags &= ~srec->msg[t]->flags; dflags &= srec->msg[t]->flags; } if (aflags | dflags) { flags_total[t]++; stats(); svars->flags_pending[t]++; fv = nfmalloc( sizeof(*fv) ); fv->aux = AUX; fv->srec = srec; fv->aflags = aflags; fv->dflags = dflags; svars->drv[t]->set_msg_flags( svars->ctx[t], srec->msg[t], srec->uid[t], aflags, dflags, flags_set, fv ); if (check_cancel( svars )) goto out; } else flags_set_p2( svars, srec, t ); } } for (t = 0; t < 2; t++) { svars->drv[t]->commit_cmds( svars->ctx[t] ); svars->state[t] |= ST_SENT_FLAGS; msgs_flags_set( svars, t ); if (check_cancel( svars )) goto out; } debug( "propagating new messages\n" ); if (UseFSync && svars->jfp) fdatasync( fileno( svars->jfp ) ); for (t = 0; t < 2; t++) { if (any_new[t]) { svars->finduid[t] = svars->drv[t]->get_uidnext( svars->ctx[t] ); JLOG( "F %d %u", (t, svars->finduid[t]), "save UIDNEXT of %s", str_fn[t] ); svars->new_msgs[t] = svars->msgs[1-t]; } else { svars->state[t] |= ST_SENT_NEW; } msgs_copied( svars, t ); if (check_cancel( svars )) goto out; } out: sync_deref( svars ); } static void msg_copied( int sts, uint uid, copy_vars_t *vars ) { SVARS_CHECK_CANCEL_RET; sync_rec_t *srec = vars->srec; switch (sts) { case SYNC_OK: if (!(srec->wstate & W_UPGRADE) && vars->msg->flags != srec->flags) { srec->flags = vars->msg->flags; JLOG( "* %u %u %u", (srec->uid[F], srec->uid[N], srec->flags), "%sed with flags", str_hl[t] ); } if (!uid) { // Stored to a non-UIDPLUS mailbox svars->state[t] |= ST_FIND_NEW; } else { ASSIGN_UID( srec, t, uid, "%sed message", str_hl[t] ); } break; case SYNC_NOGOOD: srec->status = S_DEAD; JLOG( "- %u %u", (srec->uid[F], srec->uid[N]), "%s failed", str_hl[t] ); break; default: cancel_sync( svars ); free( vars ); return; } free( vars ); new_done[t]++; stats(); svars->new_pending[t]--; msgs_copied( svars, t ); } static void msgs_found_new( int sts, message_t *msgs, void *aux ); static void msgs_new_done( sync_vars_t *svars, int t ); static void sync_close( sync_vars_t *svars, int t ); static void msgs_copied( sync_vars_t *svars, int t ) { message_t *tmsg; sync_rec_t *srec; copy_vars_t *cv; if (svars->state[t] & ST_SENDING_NEW) return; sync_ref( svars ); if (!(svars->state[t] & ST_SENT_NEW)) { for (tmsg = svars->new_msgs[t]; tmsg; tmsg = tmsg->next) { if ((srec = tmsg->srec) && (srec->status & S_PENDING)) { if (svars->drv[t]->get_memory_usage( svars->ctx[t] ) >= BufferLimit) { svars->new_msgs[t] = tmsg; goto out; } for (uint i = 0; i < TUIDL; i++) { uchar c = arc4_getbyte() & 0x3f; srec->tuid[i] = (char)(c < 26 ? c + 'A' : c < 52 ? c + 'a' - 26 : c < 62 ? c + '0' - 52 : c == 62 ? '+' : '/'); } JLOG( "# %u %u %." stringify(TUIDL) "s", (srec->uid[F], srec->uid[N], srec->tuid), "%sing message", str_hl[t] ); new_total[t]++; stats(); svars->new_pending[t]++; svars->state[t] |= ST_SENDING_NEW; cv = nfmalloc( sizeof(*cv) ); cv->cb = msg_copied; cv->aux = AUX; cv->srec = srec; cv->msg = tmsg; cv->minimal = (srec->status & S_DUMMY(t)); copy_msg( cv ); svars->state[t] &= ~ST_SENDING_NEW; if (check_cancel( svars )) goto out; } } svars->state[t] |= ST_SENT_NEW; } if (svars->new_pending[t]) goto out; sync_close( svars, 1-t ); if (check_cancel( svars )) goto out; if (svars->state[t] & ST_FIND_NEW) { debug( "finding just copied messages on %s\n", str_fn[t] ); svars->drv[t]->find_new_msgs( svars->ctx[t], svars->finduid[t], msgs_found_new, AUX ); } else { msgs_new_done( svars, t ); } out: sync_deref( svars ); } static void msgs_found_new( int sts, message_t *msgs, void *aux ) { SVARS_CHECK_RET; switch (sts) { case DRV_OK: debug( "matching just copied messages on %s\n", str_fn[t] ); break; default: warn( "Warning: cannot find newly stored messages on %s.\n", str_fn[t] ); break; } match_tuids( svars, t, msgs ); msgs_new_done( svars, t ); } static void msgs_new_done( sync_vars_t *svars, int t ) { svars->state[t] |= ST_FOUND_NEW; sync_close( svars, t ); } static void flags_set( int sts, void *aux ) { SVARS_CHECK_RET_VARS(flag_vars_t); sync_rec_t *srec = vars->srec; switch (sts) { case DRV_OK: if (vars->aflags & F_DELETED) srec->wstate |= W_DEL(t); else if (vars->dflags & F_DELETED) srec->wstate &= ~W_DEL(t); flags_set_p2( svars, srec, t ); break; } free( vars ); flags_done[t]++; stats(); svars->flags_pending[t]--; msgs_flags_set( svars, t ); } static void flags_set_p2( sync_vars_t *svars, sync_rec_t *srec, int t ) { if (srec->wstate & W_DELETE) { JLOG( "%c %u %u 0", ("><"[t], srec->uid[F], srec->uid[N]), "%sed deletion", str_hl[t] ); srec->uid[1-t] = 0; } else { uchar nflags = (srec->flags | srec->aflags[t]) & ~srec->dflags[t]; if (srec->flags != nflags) { JLOG( "* %u %u %u", (srec->uid[F], srec->uid[N], nflags), "%sed flags; were %u", (str_hl[t], srec->flags) ); srec->flags = nflags; } if (t == N) { uchar nex = (srec->wstate / W_NEXPIRE) & 1; if (nex != ((srec->status / S_EXPIRED) & 1)) { srec->status = (srec->status & ~S_EXPIRED) | (nex * S_EXPIRED); JLOG( "~ %u %u %u", (srec->uid[F], srec->uid[N], srec->status), "expired %d - commit", nex ); } else if (nex != ((srec->status / S_EXPIRE) & 1)) { srec->status = (srec->status & ~S_EXPIRE) | (nex * S_EXPIRE); JLOG( "~ %u %u %u", (srec->uid[F], srec->uid[N], srec->status), "expire %d - cancel", nex ); } } } } typedef struct { void *aux; message_t *msg; } trash_vars_t; static void msg_trashed( int sts, void *aux ); static void msg_rtrashed( int sts, uint uid, copy_vars_t *vars ); static void msgs_flags_set( sync_vars_t *svars, int t ) { message_t *tmsg; trash_vars_t *tv; copy_vars_t *cv; if (!(svars->state[t] & ST_SENT_FLAGS) || svars->flags_pending[t]) return; sync_ref( svars ); if ((svars->chan->ops[t] & OP_EXPUNGE) && (svars->ctx[t]->conf->trash || (svars->ctx[1-t]->conf->trash && svars->ctx[1-t]->conf->trash_remote_new))) { debug( "trashing on %s\n", str_fn[t] ); for (tmsg = svars->msgs[t]; tmsg; tmsg = tmsg->next) if ((tmsg->flags & F_DELETED) && !find_uint_array( svars->trashed_msgs[t].array, tmsg->uid ) && (t == F || !tmsg->srec || !(tmsg->srec->status & (S_EXPIRE|S_EXPIRED)))) { if (svars->ctx[t]->conf->trash) { if (!svars->ctx[t]->conf->trash_only_new || !tmsg->srec || (tmsg->srec->status & (S_PENDING | S_SKIPPED))) { debug( "%s: trashing message %u\n", str_fn[t], tmsg->uid ); trash_total[t]++; stats(); svars->trash_pending[t]++; tv = nfmalloc( sizeof(*tv) ); tv->aux = AUX; tv->msg = tmsg; svars->drv[t]->trash_msg( svars->ctx[t], tmsg, msg_trashed, tv ); if (check_cancel( svars )) goto out; } else debug( "%s: not trashing message %u - not new\n", str_fn[t], tmsg->uid ); } else { if (!tmsg->srec || (tmsg->srec->status & (S_PENDING | S_SKIPPED))) { if (tmsg->size <= svars->ctx[1-t]->conf->max_size) { debug( "%s: remote trashing message %u\n", str_fn[t], tmsg->uid ); trash_total[t]++; stats(); svars->trash_pending[t]++; cv = nfmalloc( sizeof(*cv) ); cv->cb = msg_rtrashed; cv->aux = INV_AUX; cv->srec = NULL; cv->msg = tmsg; cv->minimal = 0; copy_msg( cv ); if (check_cancel( svars )) goto out; } else debug( "%s: not remote trashing message %u - too big\n", str_fn[t], tmsg->uid ); } else debug( "%s: not remote trashing message %u - not new\n", str_fn[t], tmsg->uid ); } } } svars->state[t] |= ST_SENT_TRASH; sync_close( svars, t ); out: sync_deref( svars ); } static void msg_trashed( int sts, void *aux ) { trash_vars_t *vars = (trash_vars_t *)aux; DECL_SVARS; if (sts == DRV_MSG_BAD) sts = DRV_BOX_BAD; if (check_ret( sts, vars->aux )) return; INIT_SVARS(vars->aux); JLOG( "T %d %u", (t, vars->msg->uid), "trashed on %s", str_fn[t] ); free( vars ); trash_done[t]++; stats(); svars->trash_pending[t]--; sync_close( svars, t ); } static void msg_rtrashed( int sts, uint uid ATTR_UNUSED, copy_vars_t *vars ) { SVARS_CHECK_CANCEL_RET; switch (sts) { case SYNC_OK: case SYNC_NOGOOD: /* the message is gone or heavily busted */ break; default: cancel_sync( svars ); free( vars ); return; } t ^= 1; JLOG( "T %d %u", (t, vars->msg->uid), "trashed remotely on %s", str_fn[1-t] ); free( vars ); trash_done[t]++; stats(); svars->trash_pending[t]--; sync_close( svars, t ); } static void box_closed( int sts, void *aux ); static void box_closed_p2( sync_vars_t *svars, int t ); static void sync_close( sync_vars_t *svars, int t ) { if ((~svars->state[t] & (ST_FOUND_NEW|ST_SENT_TRASH)) || svars->trash_pending[t] || !(svars->state[1-t] & ST_SENT_NEW) || svars->new_pending[1-t]) return; if (svars->state[t] & ST_CLOSING) return; svars->state[t] |= ST_CLOSING; if ((svars->chan->ops[t] & OP_EXPUNGE) /*&& !(svars->state[t] & ST_TRASH_BAD)*/) { debug( "expunging %s\n", str_fn[t] ); svars->drv[t]->close_box( svars->ctx[t], box_closed, AUX ); } else { box_closed_p2( svars, t ); } } static void box_closed( int sts, void *aux ) { SVARS_CHECK_RET; svars->state[t] |= ST_DID_EXPUNGE; box_closed_p2( svars, t ); } static void box_closed_p2( sync_vars_t *svars, int t ) { sync_rec_t *srec; svars->state[t] |= ST_CLOSED; if (!(svars->state[1-t] & ST_CLOSED)) return; // All the journalling done in this function is merely for the autotest - // the operations are idempotent, and we're about to commit the new state // right afterwards anyway. for (t = 0; t < 2; t++) { // Committing maxuid is delayed until all messages were propagated, to // ensure that all pending messages are still loaded next time in case // of interruption - in particular skipping big messages would otherwise // up the limit too early. if (svars->maxuid[t] != svars->oldmaxuid[t]) JLOG( "N %d %u", (t, svars->maxuid[t]), "up maxuid of %s", str_fn[t] ); } if (((svars->state[F] | svars->state[N]) & ST_DID_EXPUNGE) || svars->chan->max_messages) { debug( "purging obsolete entries\n" ); for (srec = svars->srecs; srec; srec = srec->next) { if (srec->status & S_DEAD) continue; if (!srec->uid[N] || ((srec->wstate & W_DEL(N)) && (svars->state[N] & ST_DID_EXPUNGE))) { if (!srec->uid[F] || ((srec->wstate & W_DEL(F)) && (svars->state[F] & ST_DID_EXPUNGE)) || ((srec->status & S_EXPIRED) && svars->maxuid[F] >= srec->uid[F] && svars->maxxfuid >= srec->uid[F])) { JLOG( "- %u %u", (srec->uid[F], srec->uid[N]), "killing" ); srec->status = S_DEAD; } else if (srec->uid[N]) { JLOG( "> %u %u 0", (srec->uid[F], srec->uid[N]), "orphaning" ); srec->uid[N] = 0; } } else if (srec->uid[F] && ((srec->wstate & W_DEL(F)) && (svars->state[F] & ST_DID_EXPUNGE))) { JLOG( "< %u %u 0", (srec->uid[F], srec->uid[N]), "orphaning" ); srec->uid[F] = 0; } } } // This is just an optimization, so it needs no journaling of intermediate states. // However, doing it before the entry purge would require ensuring that the // exception list includes all relevant messages. if (svars->maxxfuid != svars->oldmaxxfuid) JLOG( "! %u", svars->maxxfuid, "max expired UID on far side" ); save_state( svars ); sync_bail( svars ); } static void sync_bail( sync_vars_t *svars ) { sync_rec_t *srec, *nsrec; free( svars->trashed_msgs[F].array.data ); free( svars->trashed_msgs[N].array.data ); for (srec = svars->srecs; srec; srec = nsrec) { nsrec = srec->next; free( srec ); } if (svars->lfd >= 0) { unlink( svars->lname ); close( svars->lfd ); } sync_bail2( svars ); } static void sync_bail2( sync_vars_t *svars ) { free( svars->lname ); free( svars->nname ); free( svars->jname ); free( svars->dname ); sync_bail3( svars ); } static void sync_bail3( sync_vars_t *svars ) { free( svars->box_name[F] ); free( svars->box_name[N] ); sync_deref( svars ); } static void sync_deref( sync_vars_t *svars ) { if (!--svars->ref_count) { void (*cb)( int sts, void *aux ) = svars->cb; void *aux = svars->aux; int ret = svars->ret; free( svars ); cb( ret, aux ); } } isync-1.4.4/src/config.c0000644000175000001440000003370714006611550011772 00000000000000/* * mbsync - mailbox synchronizer * Copyright (C) 2000-2002 Michael R. Elkins * Copyright (C) 2002-2006,2011 Oswald Buddenhagen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * As a special exception, mbsync may be linked with the OpenSSL library, * despite that library's more restrictive license. */ #include "config.h" #include "sync.h" #include #include #include #include #include #include #include #include #include static store_conf_t *stores; char * get_arg( conffile_t *cfile, int required, int *comment ) { char *ret, *p, *t; int escaped, quoted; char c; p = cfile->rest; assert( p ); while ((c = *p) && isspace( (uchar)c )) p++; if (!c || c == '#') { if (comment) *comment = (c == '#'); if (required) { error( "%s:%d: parameter missing\n", cfile->file, cfile->line ); cfile->err = 1; } ret = NULL; } else { for (escaped = 0, quoted = 0, ret = t = p; c; c = *p) { p++; if (escaped && c >= 32) { escaped = 0; *t++ = c; } else if (c == '\\') escaped = 1; else if (c == '"') quoted ^= 1; else if (!quoted && isspace( (uchar)c )) break; else *t++ = c; } *t = 0; if (escaped) { error( "%s:%d: unterminated escape sequence\n", cfile->file, cfile->line ); cfile->err = 1; ret = NULL; } if (quoted) { error( "%s:%d: missing closing quote\n", cfile->file, cfile->line ); cfile->err = 1; ret = NULL; } } cfile->rest = p; return ret; } char parse_bool( conffile_t *cfile ) { if (!strcasecmp( cfile->val, "yes" ) || !strcasecmp( cfile->val, "true" ) || !strcasecmp( cfile->val, "on" ) || !strcmp( cfile->val, "1" )) return 1; if (strcasecmp( cfile->val, "no" ) && strcasecmp( cfile->val, "false" ) && strcasecmp( cfile->val, "off" ) && strcmp( cfile->val, "0" )) { error( "%s:%d: invalid boolean value '%s'\n", cfile->file, cfile->line, cfile->val ); cfile->err = 1; } return 0; } int parse_int( conffile_t *cfile ) { char *p; int ret; ret = strtol( cfile->val, &p, 10 ); if (*p) { error( "%s:%d: invalid integer value '%s'\n", cfile->file, cfile->line, cfile->val ); cfile->err = 1; return 0; } return ret; } uint parse_size( conffile_t *cfile ) { char *p; uint ret; ret = strtoul( cfile->val, &p, 10 ); if (*p == 'k' || *p == 'K') ret *= 1024, p++; else if (*p == 'm' || *p == 'M') ret *= 1024 * 1024, p++; if (*p == 'b' || *p == 'B') p++; if (*p) { fprintf (stderr, "%s:%d: invalid size '%s'\n", cfile->file, cfile->line, cfile->val); cfile->err = 1; return 0; } return ret; } static const struct { int op; const char *name; } boxOps[] = { { OP_EXPUNGE, "Expunge" }, { OP_CREATE, "Create" }, { OP_REMOVE, "Remove" }, }; static int getopt_helper( conffile_t *cfile, int *cops, channel_conf_t *conf ) { char *arg; uint i; if (!strcasecmp( "Sync", cfile->cmd )) { arg = cfile->val; do if (!strcasecmp( "Push", arg )) *cops |= XOP_PUSH; else if (!strcasecmp( "Pull", arg )) *cops |= XOP_PULL; else if (!strcasecmp( "ReNew", arg )) *cops |= OP_RENEW; else if (!strcasecmp( "New", arg )) *cops |= OP_NEW; else if (!strcasecmp( "Delete", arg )) *cops |= OP_DELETE; else if (!strcasecmp( "Flags", arg )) *cops |= OP_FLAGS; else if (!strcasecmp( "PullReNew", arg )) conf->ops[N] |= OP_RENEW; else if (!strcasecmp( "PullNew", arg )) conf->ops[N] |= OP_NEW; else if (!strcasecmp( "PullDelete", arg )) conf->ops[N] |= OP_DELETE; else if (!strcasecmp( "PullFlags", arg )) conf->ops[N] |= OP_FLAGS; else if (!strcasecmp( "PushReNew", arg )) conf->ops[F] |= OP_RENEW; else if (!strcasecmp( "PushNew", arg )) conf->ops[F] |= OP_NEW; else if (!strcasecmp( "PushDelete", arg )) conf->ops[F] |= OP_DELETE; else if (!strcasecmp( "PushFlags", arg )) conf->ops[F] |= OP_FLAGS; else if (!strcasecmp( "All", arg ) || !strcasecmp( "Full", arg )) *cops |= XOP_PULL|XOP_PUSH; else if (strcasecmp( "None", arg ) && strcasecmp( "Noop", arg )) { error( "%s:%d: invalid Sync arg '%s'\n", cfile->file, cfile->line, arg ); cfile->err = 1; } while ((arg = get_arg( cfile, ARG_OPTIONAL, NULL ))); conf->ops[F] |= XOP_HAVE_TYPE; } else if (!strcasecmp( "SyncState", cfile->cmd )) conf->sync_state = expand_strdup( cfile->val ); else if (!strcasecmp( "CopyArrivalDate", cfile->cmd )) conf->use_internal_date = parse_bool( cfile ); else if (!strcasecmp( "MaxMessages", cfile->cmd )) conf->max_messages = parse_int( cfile ); else if (!strcasecmp( "ExpireUnread", cfile->cmd )) conf->expire_unread = parse_bool( cfile ); else { for (i = 0; i < as(boxOps); i++) { if (!strcasecmp( boxOps[i].name, cfile->cmd )) { int op = boxOps[i].op; arg = cfile->val; do { if (!strcasecmp( "Both", arg )) { *cops |= op; } else if (!strcasecmp( "Far", arg )) { conf->ops[F] |= op; } else if (!strcasecmp( "Master", arg )) { // Pre-1.4 legacy conf->ops[F] |= op; cfile->ms_warn = 1; } else if (!strcasecmp( "Near", arg )) { conf->ops[N] |= op; } else if (!strcasecmp( "Slave", arg )) { // Pre-1.4 legacy conf->ops[N] |= op; cfile->ms_warn = 1; } else if (strcasecmp( "None", arg )) { error( "%s:%d: invalid %s arg '%s'\n", cfile->file, cfile->line, boxOps[i].name, arg ); cfile->err = 1; } } while ((arg = get_arg( cfile, ARG_OPTIONAL, NULL ))); conf->ops[F] |= op * (XOP_HAVE_EXPUNGE / OP_EXPUNGE); return 1; } } return 0; } return 1; } int getcline( conffile_t *cfile ) { char *arg; int comment; if (cfile->rest && (arg = get_arg( cfile, ARG_OPTIONAL, NULL ))) { error( "%s:%d: excess token '%s'\n", cfile->file, cfile->line, arg ); cfile->err = 1; } while (fgets( cfile->buf, cfile->bufl, cfile->fp )) { cfile->line++; cfile->rest = cfile->buf; if (!(cfile->cmd = get_arg( cfile, ARG_OPTIONAL, &comment ))) { if (comment) continue; return 1; } if (!(cfile->val = get_arg( cfile, ARG_REQUIRED, NULL ))) continue; return 1; } return 0; } /* XXX - this does not detect None conflicts ... */ int merge_ops( int cops, int ops[] ) { int aops, op; uint i; aops = ops[F] | ops[N]; if (ops[F] & XOP_HAVE_TYPE) { if (aops & OP_MASK_TYPE) { if (aops & cops & OP_MASK_TYPE) { cfl: error( "Conflicting Sync args specified.\n" ); return 1; } ops[F] |= cops & OP_MASK_TYPE; ops[N] |= cops & OP_MASK_TYPE; if (cops & XOP_PULL) { if (ops[N] & OP_MASK_TYPE) goto cfl; ops[N] |= OP_MASK_TYPE; } if (cops & XOP_PUSH) { if (ops[F] & OP_MASK_TYPE) goto cfl; ops[F] |= OP_MASK_TYPE; } } else if (cops & (OP_MASK_TYPE|XOP_MASK_DIR)) { if (!(cops & OP_MASK_TYPE)) cops |= OP_MASK_TYPE; else if (!(cops & XOP_MASK_DIR)) cops |= XOP_PULL|XOP_PUSH; if (cops & XOP_PULL) ops[N] |= cops & OP_MASK_TYPE; if (cops & XOP_PUSH) ops[F] |= cops & OP_MASK_TYPE; } } for (i = 0; i < as(boxOps); i++) { op = boxOps[i].op; if (ops[F] & (op * (XOP_HAVE_EXPUNGE / OP_EXPUNGE))) { if (aops & cops & op) { error( "Conflicting %s args specified.\n", boxOps[i].name ); return 1; } ops[F] |= cops & op; ops[N] |= cops & op; } } return 0; } int load_config( const char *where ) { conffile_t cfile; store_conf_t *store, **storeapp = &stores; channel_conf_t *channel, **channelapp = &channels; group_conf_t *group, **groupapp = &groups; string_list_t *chanlist, **chanlistapp; char *arg, *p; uint len, max_size; int cops, gcops, glob_ok, fn, i; char path[_POSIX_PATH_MAX]; char buf[1024]; if (!where) { nfsnprintf( path, sizeof(path), "%s/." EXE "rc", Home ); cfile.file = path; } else cfile.file = where; info( "Reading configuration file %s\n", cfile.file ); if (!(cfile.fp = fopen( cfile.file, "r" ))) { sys_error( "Cannot open config file '%s'", cfile.file ); return 1; } buf[sizeof(buf) - 1] = 0; cfile.buf = buf; cfile.bufl = sizeof(buf) - 1; cfile.line = 0; cfile.err = 0; cfile.ms_warn = 0; cfile.rest = NULL; gcops = 0; glob_ok = 1; global_conf.expire_unread = -1; reloop: while (getcline( &cfile )) { if (!cfile.cmd) continue; for (i = 0; i < N_DRIVERS; i++) if (drivers[i]->parse_store( &cfile, &store )) { if (store) { if (!store->max_size) store->max_size = UINT_MAX; if (!store->flat_delim) store->flat_delim = ""; *storeapp = store; storeapp = &store->next; *storeapp = NULL; } glob_ok = 0; goto reloop; } if (!strcasecmp( "Channel", cfile.cmd )) { channel = nfcalloc( sizeof(*channel) ); channel->name = nfstrdup( cfile.val ); channel->max_messages = global_conf.max_messages; channel->expire_unread = global_conf.expire_unread; channel->use_internal_date = global_conf.use_internal_date; cops = 0; max_size = UINT_MAX; while (getcline( &cfile ) && cfile.cmd) { if (!strcasecmp( "MaxSize", cfile.cmd )) max_size = parse_size( &cfile ); else if (!strcasecmp( "Pattern", cfile.cmd ) || !strcasecmp( "Patterns", cfile.cmd )) { arg = cfile.val; do add_string_list( &channel->patterns, arg ); while ((arg = get_arg( &cfile, ARG_OPTIONAL, NULL ))); } else if (!strcasecmp( "Far", cfile.cmd )) { fn = F; goto linkst; } else if (!strcasecmp( "Master", cfile.cmd )) { // Pre-1.4 legacy fn = F; goto olinkst; } else if (!strcasecmp( "Near", cfile.cmd )) { fn = N; goto linkst; } else if (!strcasecmp( "Slave", cfile.cmd )) { // Pre-1.4 legacy fn = N; olinkst: cfile.ms_warn = 1; linkst: if (*cfile.val != ':' || !(p = strchr( cfile.val + 1, ':' ))) { error( "%s:%d: malformed mailbox spec\n", cfile.file, cfile.line ); cfile.err = 1; continue; } *p = 0; for (store = stores; store; store = store->next) if (!strcmp( store->name, cfile.val + 1 )) { channel->stores[fn] = store; goto stpcom; } error( "%s:%d: unknown store '%s'\n", cfile.file, cfile.line, cfile.val + 1 ); cfile.err = 1; continue; stpcom: if (*++p) channel->boxes[fn] = nfstrdup( p ); } else if (!getopt_helper( &cfile, &cops, channel )) { error( "%s:%d: keyword '%s' is not recognized in Channel sections\n", cfile.file, cfile.line, cfile.cmd ); cfile.err = 1; } } if (!channel->stores[F]) { error( "channel '%s' refers to no far side store\n", channel->name ); cfile.err = 1; } else if (!channel->stores[N]) { error( "channel '%s' refers to no near side store\n", channel->name ); cfile.err = 1; } else if (merge_ops( cops, channel->ops )) cfile.err = 1; else { if (max_size != UINT_MAX) { if (!max_size) max_size = UINT_MAX; channel->stores[F]->max_size = channel->stores[N]->max_size = max_size; } *channelapp = channel; channelapp = &channel->next; } glob_ok = 0; goto reloop; } else if (!strcasecmp( "Group", cfile.cmd )) { group = nfmalloc( sizeof(*group) ); group->name = nfstrdup( cfile.val ); *groupapp = group; groupapp = &group->next; *groupapp = NULL; chanlistapp = &group->channels; *chanlistapp = NULL; while ((arg = get_arg( &cfile, ARG_OPTIONAL, NULL ))) { addone: len = strlen( arg ); chanlist = nfmalloc( sizeof(*chanlist) + len ); memcpy( chanlist->string, arg, len + 1 ); *chanlistapp = chanlist; chanlistapp = &chanlist->next; *chanlistapp = NULL; } while (getcline( &cfile ) && cfile.cmd) { if (!strcasecmp( "Channel", cfile.cmd ) || !strcasecmp( "Channels", cfile.cmd )) { arg = cfile.val; goto addone; } else { error( "%s:%d: keyword '%s' is not recognized in Group sections\n", cfile.file, cfile.line, cfile.cmd ); cfile.err = 1; } } glob_ok = 0; goto reloop; } else if (!strcasecmp( "FSync", cfile.cmd )) { UseFSync = parse_bool( &cfile ); } else if (!strcasecmp( "FieldDelimiter", cfile.cmd )) { if (strlen( cfile.val ) != 1) { error( "%s:%d: Field delimiter must be exactly one character long\n", cfile.file, cfile.line ); cfile.err = 1; } else { FieldDelimiter = cfile.val[0]; if (!ispunct( FieldDelimiter )) { error( "%s:%d: Field delimiter must be a punctuation character\n", cfile.file, cfile.line ); cfile.err = 1; } } } else if (!strcasecmp( "BufferLimit", cfile.cmd )) { BufferLimit = parse_size( &cfile ); if (!BufferLimit) { error( "%s:%d: BufferLimit cannot be zero\n", cfile.file, cfile.line ); cfile.err = 1; } } else if (!getopt_helper( &cfile, &gcops, &global_conf )) { error( "%s:%d: '%s' is not a recognized section-starting or global keyword\n", cfile.file, cfile.line, cfile.cmd ); cfile.err = 1; while (getcline( &cfile )) if (!cfile.cmd) goto reloop; break; } if (!glob_ok) { error( "%s:%d: global options may not follow sections\n", cfile.file, cfile.line ); cfile.err = 1; } } fclose (cfile.fp); if (cfile.ms_warn) warn( "Notice: Master/Slave are deprecated; use Far/Near instead.\n" ); cfile.err |= merge_ops( gcops, global_conf.ops ); if (!global_conf.sync_state) global_conf.sync_state = expand_strdup( "~/." EXE "/" ); return cfile.err; } isync-1.4.4/src/tst_timers.c0000644000175000001440000000564614006611550012723 00000000000000/* * mbsync - mailbox synchronizer * Copyright (C) 2014 Oswald Buddenhagen * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * As a special exception, mbsync may be linked with the OpenSSL library, * despite that library's more restrictive license. */ #include "common.h" #include #include #include /* Just to satisfy the references in util.c */ int DFlags; const char *Home; typedef struct { int id; int first, other, morph_at, morph_to; time_t start; wakeup_t timer; wakeup_t morph_timer; } tst_t; static void timer_start( tst_t *timer, int to ) { printf( "starting timer %d, should expire after %d\n", timer->id, to ); time( &timer->start ); conf_wakeup( &timer->timer, to ); } static void timed_out( void *aux ) { tst_t *timer = (tst_t *)aux; printf( "timer %d expired after %d, repeat %d\n", timer->id, (int)(time( 0 ) - timer->start), timer->other ); if (timer->other >= 0) { timer_start( timer, timer->other ); } else { wipe_wakeup( &timer->timer ); wipe_wakeup( &timer->morph_timer ); free( timer ); } } static void morph_timed_out( void *aux ) { tst_t *timer = (tst_t *)aux; printf( "morphing timer %d after %d\n", timer->id, (int)(time( 0 ) - timer->start) ); timer_start( timer, timer->morph_to ); } static int nextid; int main( int argc, char **argv ) { int i; for (i = 1; i < argc; i++) { char *val = argv[i]; tst_t *timer = nfmalloc( sizeof(*timer) ); init_wakeup( &timer->timer, timed_out, timer ); init_wakeup( &timer->morph_timer, morph_timed_out, timer ); timer->id = ++nextid; timer->first = strtol( val, &val, 0 ); if (*val == '@') { timer->other = timer->first; timer->first = strtol( ++val, &val, 0 ); } else { timer->other = -1; } if (*val == ':') { timer->morph_to = strtol( ++val, &val, 0 ); if (*val != '@') goto fail; timer->morph_at = strtol( ++val, &val, 0 ); } else { timer->morph_at = -1; } if (*val) { fail: fprintf( stderr, "Fatal: syntax error in %s, use [@][:@]\n", argv[i] ); return 1; } timer_start( timer, timer->first ); if (timer->morph_at >= 0) { printf( "timer %d, should morph after %d\n", timer->id, timer->morph_at ); conf_wakeup( &timer->morph_timer, timer->morph_at ); } } main_loop(); return 0; } isync-1.4.4/src/drv_maildir.c0000644000175000001440000015065014151635534013027 00000000000000/* * mbsync - mailbox synchronizer * Copyright (C) 2000-2002 Michael R. Elkins * Copyright (C) 2002-2006,2010-2013 Oswald Buddenhagen * Copyright (C) 2004 Theodore Y. Ts'o * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * As a special exception, mbsync may be linked with the OpenSSL library, * despite that library's more restrictive license. */ #include "driver.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #if !defined(_POSIX_SYNCHRONIZED_IO) || _POSIX_SYNCHRONIZED_IO <= 0 # define fdatasync fsync #endif #ifdef USE_DB #include #endif /* USE_DB */ #define SUB_UNSET 0 #define SUB_VERBATIM 1 #define SUB_MAILDIRPP 2 #define SUB_LEGACY 3 typedef union maildir_store_conf { store_conf_t gen; struct { STORE_CONF char *path; char *inbox; #ifdef USE_DB int alt_map; #endif /* USE_DB */ char info_delimiter; char sub_style; char failed; char *info_prefix, *info_stop; /* precalculated from info_delimiter */ }; } maildir_store_conf_t; typedef union maildir_message { message_t gen; struct { MESSAGE(union maildir_message) char *base; }; } maildir_message_t; typedef union maildir_store { store_t gen; struct { STORE(union maildir_store) int uvfd, uvok, is_inbox, fresh[3]; uint opts, minuid, maxuid, finduid, pairuid, newuid, uidvalidity, nuid; uint_array_t excs; char *path; // own char *trash; #ifdef USE_DB DB *db; char *usedb; #endif /* USE_DB */ string_list_t *boxes; // _list results char listed; // was _list already run with these flags? // note that the message counts do _not_ reflect stats from msgs, // but mailbox totals. also, don't trust them beyond the initial load. int total_msgs, recent_msgs; maildir_message_t *msgs; wakeup_t lcktmr; void (*bad_callback)( void *aux ); void *bad_callback_aux; }; } maildir_store_t; #ifdef USE_DB static DBT key, value; /* no need to be reentrant, and this saves lots of memset()s */ #endif /* USE_DB */ static struct flock lck; static int MaildirCount; static void ATTR_PRINTFLIKE(1, 2) debug( const char *msg, ... ) { va_list va; va_start( va, msg ); vdebug( DEBUG_SYNC, msg, va ); va_end( va ); } /* Keep the mailbox driver flag definitions in sync: */ /* grep for MAILBOX_DRIVER_FLAG */ /* The order is according to alphabetical maildir flag sort */ static const char Flags[] = { 'D', 'F', 'P', 'R', 'S', 'T' }; static uchar maildir_parse_flags( const char *info_prefix, const char *base ) { const char *s; uint i; uchar flags; flags = 0; if ((s = strstr( base, info_prefix ))) for (s += 3, i = 0; i < as(Flags); i++) if (strchr( s, Flags[i] )) flags |= (1 << i); return flags; } static int maildir_ensure_path( maildir_store_conf_t *conf ) { if (!conf->path) { error( "Maildir error: store '%s' has no Path\n", conf->name ); conf->failed = FAIL_FINAL; return -1; } return 0; } /* Subdirs of INBOX include a leading slash. */ /* Path includes a trailing slash, Inbox does not. */ static char * maildir_join_path( maildir_store_conf_t *conf, int in_inbox, const char *box ) { char *out, *p; const char *prefix; uint pl, bl, n; char c; if (in_inbox || conf->sub_style == SUB_MAILDIRPP) { prefix = conf->inbox; } else { if (maildir_ensure_path( conf ) < 0) return NULL; prefix = conf->path; } pl = strlen( prefix ); for (bl = 0, n = 0; (c = box[bl]); bl++) if (c == '/') { if (conf->sub_style == SUB_UNSET) { error( "Maildir error: accessing subfolder '%s', but store '%s' does not specify SubFolders style\n", box, conf->name ); return NULL; } n++; } else if (c == '.' && conf->sub_style == SUB_MAILDIRPP) { error( "Maildir error: store '%s', folder '%s': SubFolders style Maildir++ does not support dots in mailbox names\n", conf->name, box ); return NULL; } switch (conf->sub_style) { case SUB_VERBATIM: n = 0; break; case SUB_MAILDIRPP: n = 2; break; default: /* SUB_LEGACY and SUB_UNSET */ break; } out = nfmalloc( pl + bl + n + 1 ); memcpy( out, prefix, pl ); p = out + pl; if (conf->sub_style == SUB_MAILDIRPP) { *p++ = '/'; *p++ = '.'; } while ((c = *box++)) { if (c == '/') { switch (conf->sub_style) { case SUB_VERBATIM: *p++ = c; break; case SUB_LEGACY: *p++ = c; FALLTHROUGH default: /* SUB_MAILDIRPP */ *p++ = '.'; break; } } else { *p++ = c; } } *p = 0; return out; } static int maildir_validate_path( maildir_store_conf_t *conf ) { struct stat st; if (stat( conf->path, &st ) || !S_ISDIR(st.st_mode)) { error( "Maildir error: cannot open store '%s'\n", conf->path ); conf->failed = FAIL_FINAL; return -1; } return 0; } static void lcktmr_timeout( void *aux ); static store_t * maildir_alloc_store( store_conf_t *gconf, const char *label ATTR_UNUSED ) { maildir_store_t *ctx; ctx = nfcalloc( sizeof(*ctx) ); ctx->driver = &maildir_driver; ctx->gen.conf = gconf; ctx->uvfd = -1; init_wakeup( &ctx->lcktmr, lcktmr_timeout, ctx ); return &ctx->gen; } static void maildir_connect_store( store_t *gctx, void (*cb)( int sts, void *aux ), void *aux ) { maildir_store_t *ctx = (maildir_store_t *)gctx; maildir_store_conf_t *conf = ctx->conf; if (conf->path && maildir_validate_path( conf ) < 0) { cb( DRV_STORE_BAD, aux ); return; } if (conf->trash && !(ctx->trash = maildir_join_path( conf, 0, conf->trash ))) { cb( DRV_STORE_BAD, aux ); return; } cb( DRV_OK, aux ); } static void free_maildir_messages( maildir_message_t *msg ) { for (maildir_message_t *tmsg; (tmsg = msg); msg = tmsg) { tmsg = msg->next; free( msg->base ); free( msg ); } } static void maildir_cleanup( store_t *gctx ) { maildir_store_t *ctx = (maildir_store_t *)gctx; free_maildir_messages( ctx->msgs ); #ifdef USE_DB if (ctx->db) ctx->db->close( ctx->db, 0 ); free( ctx->usedb ); #endif /* USE_DB */ free( ctx->path ); free( ctx->excs.data ); if (ctx->uvfd >= 0) close( ctx->uvfd ); conf_wakeup( &ctx->lcktmr, -1 ); } static void maildir_free_store( store_t *gctx ) { maildir_store_t *ctx = (maildir_store_t *)gctx; maildir_cleanup( gctx ); wipe_wakeup( &ctx->lcktmr ); free( ctx->trash ); free_string_list( ctx->boxes ); free( gctx ); } static void maildir_cleanup_drv( void ) { } static void maildir_set_bad_callback( store_t *gctx, void (*cb)( void *aux ), void *aux ) { maildir_store_t *ctx = (maildir_store_t *)gctx; ctx->bad_callback = cb; ctx->bad_callback_aux = aux; } static void maildir_invoke_bad_callback( maildir_store_t *ctx ) { ctx->bad_callback( ctx->bad_callback_aux ); } static int maildir_list_maildirpp( maildir_store_t *ctx, int flags, const char *inbox ) { DIR *dir; struct dirent *de; int warned = 0; struct stat st; if (ctx->listed & LIST_PATH) // Implies LIST_INBOX return 0; if (!(ctx->listed & LIST_INBOX)) add_string_list( &ctx->boxes, "INBOX" ); char path[_POSIX_PATH_MAX]; int pathLen = nfsnprintf( path, _POSIX_PATH_MAX, "%s/", inbox ); if (!(dir = opendir( path ))) { if (errno == ENOENT || errno == ENOTDIR) return 0; sys_error( "Maildir error: cannot list %s", path ); return -1; } while ((de = readdir( dir ))) { const char *ent = de->d_name; if (*ent++ != '.' || !*ent) continue; char name[_POSIX_PATH_MAX]; char *effName = name; if (*ent == '.') { if (ctx->listed & LIST_INBOX) continue; if (!*++ent) continue; // The Maildir++ Inbox is technically not under Path (as there is none), so // "*" would never match INBOX*, which is rather unintuitive. Matching INBOX* // implicitly instead makes it consistent with an IMAP Store with an empty Path. } else { if (!(flags & (LIST_PATH | LIST_PATH_MAYBE))) continue; // Explained in maildir_list_recurse(). if (starts_with( ent, -1, "INBOX", 5 ) && (!ent[5] || ent[5] == '.')) { if (!warned) { warned = 1; path[pathLen] = 0; warn( "Maildir warning: ignoring INBOX in %s\n", path ); } continue; } effName += 6; } nfsnprintf( path + pathLen, _POSIX_PATH_MAX - pathLen, "%s/cur", de->d_name ); if (!stat( path, &st ) && S_ISDIR(st.st_mode)) { int nl = nfsnprintf( name, _POSIX_PATH_MAX, "INBOX/%s", ent ); for (int i = 6; i < nl; i++) { if (name[i] == '.') name[i] = '/'; } add_string_list( &ctx->boxes, effName ); } } closedir (dir); if (flags & (LIST_PATH | LIST_PATH_MAYBE)) ctx->listed |= LIST_PATH; ctx->listed |= LIST_INBOX; return 0; } static int maildir_list_inbox( maildir_store_t *ctx, int flags, const char *basePath ); static int maildir_list_path( maildir_store_t *ctx, int flags, const char *inbox ); static int maildir_list_recurse( maildir_store_t *ctx, int isBox, int flags, int depth, const char *inbox, uint inboxLen, const char *basePath, uint basePathLen, char *path, int pathLen, char *name, int nameLen ) { DIR *dir; int style = ctx->conf->sub_style; int pl, nl; struct dirent *de; struct stat st; if (!(dir = opendir( path ))) { if (isBox && (errno == ENOENT || errno == ENOTDIR)) return 0; sys_error( "Maildir error: cannot list %s", path ); return -1; } if (isBox > 1 && style == SUB_UNSET) { error( "Maildir error: found subfolder '%.*s', but store '%s' does not specify SubFolders style\n", nameLen - 1, name, ctx->conf->name ); closedir( dir ); return -1; } if (++depth > 10) { // We do the other checks first to avoid confusing error messages for files. error( "Maildir error: path %s is too deeply nested. Symlink loop?\n", path ); closedir( dir ); return -1; } while ((de = readdir( dir ))) { const char *ent = de->d_name; if (ent[0] == '.' && (!ent[1] || (ent[1] == '.' && !ent[2]))) continue; pl = nfsnprintf( path + pathLen, _POSIX_PATH_MAX - pathLen, "%s", ent ); if (pl == 3 && (!memcmp( ent, "cur", 3 ) || !memcmp( ent, "new", 3 ) || !memcmp( ent, "tmp", 3 ))) continue; pl += pathLen; if (inbox && equals( path, pl, inbox, inboxLen )) { // Inbox nested into Path. if (maildir_list_inbox( ctx, flags, NULL ) < 0) { closedir( dir ); return -1; } } else if (basePath && equals( path, pl, basePath, basePathLen )) { // Path nested into Inbox. if (maildir_list_path( ctx, flags, NULL ) < 0) { closedir( dir ); return -1; } } else { if (style == SUB_LEGACY) { if (*ent == '.') { if (!isBox) continue; ent++; } else { if (isBox) continue; } } // A folder named "INBOX" would be indistinguishable from the // actual INBOX after prefix stripping, so drop it. This applies // only to the fully uppercased spelling, as our canonical box // names are case-sensitive (unlike IMAP's INBOX). if (!nameLen && equals( ent, -1, "INBOX", 5 )) { path[pathLen] = 0; warn( "Maildir warning: ignoring INBOX in %s\n", path ); continue; } nl = nameLen + nfsnprintf( name + nameLen, _POSIX_PATH_MAX - nameLen, "%s", ent ); path[pl++] = '/'; nfsnprintf( path + pl, _POSIX_PATH_MAX - pl, "cur" ); if (!stat( path, &st ) && S_ISDIR(st.st_mode)) add_string_list( &ctx->boxes, name ); path[pl] = 0; name[nl++] = '/'; if (maildir_list_recurse( ctx, isBox + 1, flags, depth, inbox, inboxLen, basePath, basePathLen, path, pl, name, nl ) < 0) { closedir( dir ); return -1; } } } closedir (dir); return 0; } static int maildir_list_inbox( maildir_store_t *ctx, int flags, const char *basePath ) { char path[_POSIX_PATH_MAX], name[_POSIX_PATH_MAX]; if (ctx->listed & LIST_INBOX) return 0; ctx->listed |= LIST_INBOX; add_string_list( &ctx->boxes, "INBOX" ); return maildir_list_recurse( ctx, 1, flags, 0, NULL, 0, basePath, basePath ? strlen( basePath ) - 1 : 0, path, nfsnprintf( path, _POSIX_PATH_MAX, "%s/", ctx->conf->inbox ), name, nfsnprintf( name, _POSIX_PATH_MAX, "INBOX/" ) ); } static int maildir_list_path( maildir_store_t *ctx, int flags, const char *inbox ) { char path[_POSIX_PATH_MAX], name[_POSIX_PATH_MAX]; if (ctx->listed & LIST_PATH) return 0; ctx->listed |= LIST_PATH; if (maildir_ensure_path( ctx->conf ) < 0) return -1; return maildir_list_recurse( ctx, 0, flags, 0, inbox, inbox ? strlen( inbox ) : 0, NULL, 0, path, nfsnprintf( path, _POSIX_PATH_MAX, "%s", ctx->conf->path ), name, 0 ); } static void maildir_list_store( store_t *gctx, int flags, void (*cb)( int sts, string_list_t *boxes, void *aux ), void *aux ) { maildir_store_t *ctx = (maildir_store_t *)gctx; maildir_store_conf_t *conf = ctx->conf; if (conf->sub_style == SUB_MAILDIRPP ? maildir_list_maildirpp( ctx, flags, conf->inbox ) < 0 : ((((flags & LIST_PATH) || ((flags & LIST_PATH_MAYBE) && conf->path)) && maildir_list_path( ctx, flags, conf->inbox ) < 0) || ((flags & LIST_INBOX) && maildir_list_inbox( ctx, flags, conf->path ) < 0))) { maildir_invoke_bad_callback( ctx ); cb( DRV_CANCELED, NULL, aux ); } else { cb( DRV_OK, ctx->boxes, aux ); } } static const char *subdirs[] = { "cur", "new", "tmp" }; typedef struct { char *base; char *msgid; uint size; uint uid; uchar recent; char tuid[TUIDL]; } msg_t; DEFINE_ARRAY_TYPE(msg_t) static void maildir_free_scan( msg_t_array_alloc_t *msglist ) { uint i; if (msglist->array.data) { for (i = 0; i < msglist->array.size; i++) free( msglist->array.data[i].base ); free( msglist->array.data ); } } #define _24_HOURS (3600 * 24) static int maildir_clear_tmp( char *buf, int bufsz, int bl ) { DIR *dirp; struct dirent *entry; time_t now; struct stat st; memcpy( buf + bl, "tmp/", 5 ); bl += 4; if (!(dirp = opendir( buf ))) { sys_error( "Maildir error: cannot list %s", buf ); return DRV_BOX_BAD; } time( &now ); while ((entry = readdir( dirp ))) { nfsnprintf( buf + bl, bufsz - bl, "%s", entry->d_name ); if (stat( buf, &st )) { if (errno != ENOENT) sys_error( "Maildir error: cannot access %s", buf ); } else if (S_ISREG(st.st_mode) && now - st.st_ctime >= _24_HOURS) { /* This should happen infrequently enough that it won't be * bothersome to the user to display when it occurs. */ notice( "Maildir notice: removing stale file %s\n", buf ); if (unlink( buf ) && errno != ENOENT) sys_error( "Maildir error: cannot remove %s", buf ); } } closedir( dirp ); return DRV_OK; } static int make_box_dir( char *buf, int bl ) { char *p; if (!mkdir( buf, 0700 ) || errno == EEXIST) return 0; p = memrchr( buf, '/', (size_t)bl - 1 ); *p = 0; if (make_box_dir( buf, (int)(p - buf) )) return -1; *p = '/'; return mkdir( buf, 0700 ); } static int maildir_validate( const char *box, int create, maildir_store_t *ctx ) { int i, bl, ret; struct stat st; char buf[_POSIX_PATH_MAX]; bl = nfsnprintf( buf, sizeof(buf) - 4, "%s/", box ); if (stat( buf, &st )) { if (errno != ENOENT) { sys_error( "Maildir error: cannot access mailbox '%s'", box ); return DRV_BOX_BAD; } if (!create) return DRV_BOX_BAD; if (make_box_dir( buf, bl )) { sys_error( "Maildir error: cannot create mailbox '%s'", box ); ctx->conf->failed = FAIL_FINAL; maildir_invoke_bad_callback( ctx ); return DRV_CANCELED; } } else if (!S_ISDIR(st.st_mode)) { notdir: error( "Maildir error: '%s' is no valid mailbox\n", box ); return DRV_BOX_BAD; } for (i = 0; i < 3; i++) { memcpy( buf + bl, subdirs[i], 4 ); if (stat( buf, &st )) { /* We always create new/ and tmp/ if they are missing. cur/ is the presence indicator. */ if (!i && !create) return DRV_BOX_BAD; if (mkdir( buf, 0700 )) { sys_error( "Maildir error: cannot create directory %s", buf ); return DRV_BOX_BAD; } ctx->fresh[i] = 1; } else if (!S_ISDIR(st.st_mode)) { goto notdir; } else { if (i == 2) { if ((ret = maildir_clear_tmp( buf, sizeof(buf), bl )) != DRV_OK) return ret; } } } return DRV_OK; } #ifdef USE_DB static void make_key( const char *info_stop, DBT *tkey, const char *name ) { char *u = strpbrk( name, info_stop ); DIAG_PUSH DIAG_DISABLE("-Wcast-qual") // C has no const_cast<> ... tkey->data = (char *)name; DIAG_POP tkey->size = u ? (size_t)(u - name) : strlen( name ); } #endif /* USE_DB */ static int maildir_store_uidval( maildir_store_t *ctx ) { int n; #ifdef USE_DB int ret; uint uv[2]; #endif char buf[128]; #ifdef USE_DB if (ctx->db) { key.data = (void *)"UIDVALIDITY"; key.size = 11; uv[0] = ctx->uidvalidity; uv[1] = ctx->nuid; value.data = uv; value.size = sizeof(uv); if ((ret = ctx->db->put( ctx->db, NULL, &key, &value, 0 ))) { ctx->db->err( ctx->db, ret, "Maildir error: db->put()" ); return DRV_BOX_BAD; } if ((ret = ctx->db->sync( ctx->db, 0 ))) { ctx->db->err( ctx->db, ret, "Maildir error: db->sync()" ); return DRV_BOX_BAD; } } else #endif /* USE_DB */ { n = sprintf( buf, "%u\n%u\n", ctx->uidvalidity, ctx->nuid ); lseek( ctx->uvfd, 0, SEEK_SET ); if (write( ctx->uvfd, buf, (uint)n ) != n || ftruncate( ctx->uvfd, n ) || (UseFSync && fdatasync( ctx->uvfd ))) { error( "Maildir error: cannot write UIDVALIDITY.\n" ); return DRV_BOX_BAD; } } conf_wakeup( &ctx->lcktmr, 2 ); return DRV_OK; } static int maildir_init_uidval( maildir_store_t *ctx ) { ctx->uidvalidity = (uint)time( NULL ); ctx->nuid = 0; ctx->uvok = 0; #ifdef USE_DB if (ctx->db) { u_int32_t count; ctx->db->truncate( ctx->db, NULL, &count, 0 ); } #endif /* USE_DB */ return maildir_store_uidval( ctx ); } static int maildir_init_uidval_new( maildir_store_t *ctx ) { notice( "Maildir notice: no UIDVALIDITY, creating new.\n" ); return maildir_init_uidval( ctx ); } static int maildir_uidval_lock( maildir_store_t *ctx ) { int n; #ifdef USE_DB int ret; struct stat st; #endif char buf[128]; if (pending_wakeup( &ctx->lcktmr )) { /* The unlock timer is active, so we are obviously already locked. */ return DRV_OK; } /* This (theoretically) works over NFS. Let's hope nobody else did the same in the opposite order, as we'd deadlock then. */ #if SEEK_SET != 0 lck.l_whence = SEEK_SET; #endif lck.l_type = F_WRLCK; if (fcntl( ctx->uvfd, F_SETLKW, &lck )) { error( "Maildir error: cannot fcntl lock UIDVALIDITY.\n" ); return DRV_BOX_BAD; } #ifdef USE_DB if (ctx->usedb) { if (fstat( ctx->uvfd, &st )) { sys_error( "Maildir error: cannot fstat UID database" ); return DRV_BOX_BAD; } if (db_create( &ctx->db, NULL, 0 )) { fputs( "Maildir error: db_create() failed\n", stderr ); return DRV_BOX_BAD; } if ((ret = (ctx->db->open)( ctx->db, NULL, ctx->usedb, NULL, DB_HASH, st.st_size ? 0 : DB_CREATE | DB_TRUNCATE, 0 ))) { ctx->db->err( ctx->db, ret, "Maildir error: db->open(%s)", ctx->usedb ); return DRV_BOX_BAD; } key.data = (void *)"UIDVALIDITY"; key.size = 11; if ((ret = ctx->db->get( ctx->db, NULL, &key, &value, 0 ))) { if (ret != DB_NOTFOUND) { ctx->db->err( ctx->db, ret, "Maildir error: db->get()" ); return DRV_BOX_BAD; } return maildir_init_uidval_new( ctx ); } ctx->uidvalidity = ((uint *)value.data)[0]; ctx->nuid = ((uint *)value.data)[1]; } else #endif { lseek( ctx->uvfd, 0, SEEK_SET ); if ((n = read( ctx->uvfd, buf, sizeof(buf) - 1 )) <= 0 || (buf[n] = 0, sscanf( buf, "%u\n%u", &ctx->uidvalidity, &ctx->nuid ) != 2)) { #if 1 /* In a generic driver, resetting the UID validity would be the right thing. * But this would mess up the sync state completely. So better bail out and * give the user a chance to fix the mailbox. */ if (n) { error( "Maildir error: cannot read UIDVALIDITY.\n" ); return DRV_BOX_BAD; } #endif return maildir_init_uidval_new( ctx ); } } ctx->uvok = 1; conf_wakeup( &ctx->lcktmr, 2 ); return DRV_OK; } static void maildir_uidval_unlock( maildir_store_t *ctx ) { #ifdef USE_DB if (ctx->db) { ctx->db->close( ctx->db, 0 ); ctx->db = NULL; } #endif /* USE_DB */ lck.l_type = F_UNLCK; fcntl( ctx->uvfd, F_SETLK, &lck ); } static void lcktmr_timeout( void *aux ) { maildir_uidval_unlock( (maildir_store_t *)aux ); } static int maildir_obtain_uid( maildir_store_t *ctx, uint *uid ) { int ret; if ((ret = maildir_uidval_lock( ctx )) != DRV_OK) return ret; *uid = ++ctx->nuid; return maildir_store_uidval( ctx ); } #ifdef USE_DB static int maildir_set_uid( maildir_store_t *ctx, const char *name, uint *uid ) { int ret; if ((ret = maildir_uidval_lock( ctx )) != DRV_OK) return ret; *uid = ++ctx->nuid; make_key( ctx->conf->info_stop, &key, name ); value.data = uid; value.size = sizeof(*uid); if ((ret = ctx->db->put( ctx->db, NULL, &key, &value, 0 ))) { ctx->db->err( ctx->db, ret, "Maildir error: db->put()" ); return DRV_BOX_BAD; } return maildir_store_uidval( ctx ); } #endif static int maildir_compare( const void *l, const void *r ) { const msg_t *lm = (const msg_t *)l, *rm = (const msg_t *)r; char *ldot, *rdot, *ldot2, *rdot2, *lseq, *rseq; uint llen, rlen; int ret; if (lm->uid != rm->uid) // Can't subtract, the result might not fit into signed int. return lm->uid > rm->uid ? 1 : -1; /* No UID, so sort by arrival date. We should not do this, but we rely on the suggested unique file name scheme - we have no choice. */ /* The first field are always the seconds. Alphabetical sort should be faster than numeric. */ if (!(ldot = strchr( lm->base, '.' )) || !(rdot = strchr( rm->base, '.' ))) goto stronly; /* Should never happen ... */ llen = (uint)(ldot - lm->base), rlen = (uint)(rdot - rm->base); /* The shorter number is smaller. Really. This won't trigger with any mail created after Sep 9 2001 anyway. */ if ((ret = (int)llen - (int)rlen)) return ret; if ((ret = memcmp( lm->base, rm->base, llen ))) return ret; ldot++, rdot++; if ((llen = strtoul( ldot, &ldot2, 10 ))) { if (!(rlen = strtoul( rdot, &rdot2, 10 ))) goto stronly; /* Comparing apples to oranges ... */ /* Classical PID specs */ if ((ret = (int)llen - (int)rlen)) { retpid: /* Handle PID wraparound. This works only on systems where PIDs are not reused too fast */ if (ret > 20000 || ret < -20000) ret = -ret; return ret; } return (*ldot2 != '_' ? 0 : atoi( ldot2 + 1 )) - (*rdot2 != '_' ? 0 : atoi( rdot2 + 1 )); } if (!(ldot2 = strchr( ldot, '.' )) || !(rdot2 = strchr( rdot, '.' ))) goto stronly; /* Should never happen ... */ llen = (uint)(ldot2 - ldot), rlen = (uint)(rdot2 - rdot); if (((lseq = memchr( ldot, '#', llen )) && (rseq = memchr( rdot, '#', rlen ))) || ((lseq = memchr( ldot, 'M', llen )) && (rseq = memchr( rdot, 'M', rlen )))) return atoi( lseq + 1 ) - atoi( rseq + 1 ); if ((lseq = memchr( ldot, 'P', llen )) && (rseq = memchr( rdot, 'P', rlen ))) { if ((ret = atoi( lseq + 1 ) - atoi( rseq + 1 ))) goto retpid; if ((lseq = memchr( ldot, 'Q', llen )) && (rseq = memchr( rdot, 'Q', rlen ))) return atoi( lseq + 1 ) - atoi( rseq + 1 ); } stronly: /* Fall-back, so the sort order is defined at all */ return strcmp( lm->base, rm->base ); } static int maildir_scan( maildir_store_t *ctx, msg_t_array_alloc_t *msglist ) { maildir_store_conf_t *conf = ctx->conf; DIR *d; FILE *f; struct dirent *e; const char *u, *ru; #ifdef USE_DB DB *tdb; DBC *dbc; #endif /* USE_DB */ msg_t *entry; uint i; int bl, fnl, ret; uint uid; time_t now, stamps[2]; struct stat st; char buf[_POSIX_PATH_MAX], nbuf[_POSIX_PATH_MAX]; again: ARRAY_INIT( msglist ); ctx->total_msgs = ctx->recent_msgs = 0; if (ctx->uvok || ctx->maxuid == UINT_MAX) { #ifdef USE_DB if (ctx->usedb) { if (db_create( &tdb, NULL, 0 )) { fputs( "Maildir error: db_create() failed\n", stderr ); return DRV_BOX_BAD; } if ((tdb->open)( tdb, NULL, NULL, NULL, DB_HASH, DB_CREATE, 0 )) { fputs( "Maildir error: tdb->open() failed\n", stderr ); bork: tdb->close( tdb, 0 ); return DRV_BOX_BAD; } } #endif /* USE_DB */ bl = nfsnprintf( buf, sizeof(buf) - 4, "%s/", ctx->path ); restat: now = time( NULL ); for (i = 0; i < 2; i++) { memcpy( buf + bl, subdirs[i], 4 ); if (stat( buf, &st )) { sys_error( "Maildir error: cannot stat %s", buf ); goto dfail; } if (st.st_mtime == now && !(DFlags & ZERODELAY) && !ctx->fresh[i]) { /* If the modification happened during this second, we wouldn't be able to * tell if there were further modifications during this second. So wait. * This has the nice side effect that we wait for "batches" of changes to * complete. On the downside, it can potentially block indefinitely. */ notice( "Maildir notice: sleeping due to recent directory modification.\n" ); sleep( 1 ); /* FIXME: should make this async */ goto restat; } stamps[i] = st.st_mtime; } for (i = 0; i < 2; i++) { memcpy( buf + bl, subdirs[i], 4 ); if (!(d = opendir( buf ))) { sys_error( "Maildir error: cannot list %s", buf ); rfail: maildir_free_scan( msglist ); dfail: #ifdef USE_DB if (ctx->usedb) tdb->close( tdb, 0 ); #endif /* USE_DB */ return DRV_BOX_BAD; } while ((e = readdir( d ))) { if (*e->d_name == '.') continue; ctx->total_msgs++; ctx->recent_msgs += i; #ifdef USE_DB if (ctx->usedb) { if (maildir_uidval_lock( ctx ) != DRV_OK) goto mbork; make_key( conf->info_stop, &key, e->d_name ); if ((ret = ctx->db->get( ctx->db, NULL, &key, &value, 0 ))) { if (ret != DB_NOTFOUND) { ctx->db->err( ctx->db, ret, "Maildir error: db->get()" ); mbork: maildir_free_scan( msglist ); closedir( d ); goto bork; } uid = UINT_MAX; } else { value.size = 0; if ((ret = tdb->put( tdb, NULL, &key, &value, 0 ))) { tdb->err( tdb, ret, "Maildir error: tdb->put()" ); goto mbork; } uid = *(uint *)value.data; } } else #endif /* USE_DB */ { uid = (ctx->uvok && (u = strstr( e->d_name, ",U=" ))) ? strtoul( u + 3, NULL, 10 ) : 0; if (!uid) uid = UINT_MAX; } if (uid <= ctx->maxuid) { if (uid < ctx->minuid && !find_uint_array( ctx->excs, uid )) continue; entry = msg_t_array_append( msglist ); entry->base = nfstrdup( e->d_name ); entry->msgid = NULL; entry->uid = uid; entry->recent = (uchar)i; entry->size = 0; entry->tuid[0] = 0; } } closedir( d ); } for (i = 0; i < 2; i++) { memcpy( buf + bl, subdirs[i], 4 ); if (stat( buf, &st )) { sys_error( "Maildir error: cannot re-stat %s", buf ); goto rfail; } if (st.st_mtime != stamps[i]) { /* Somebody messed with the mailbox since we started listing it. */ #ifdef USE_DB if (ctx->usedb) tdb->close( tdb, 0 ); #endif /* USE_DB */ maildir_free_scan( msglist ); goto again; } } #ifdef USE_DB if (ctx->usedb) { if (maildir_uidval_lock( ctx ) != DRV_OK) ; else if ((ret = ctx->db->cursor( ctx->db, NULL, &dbc, 0 ))) ctx->db->err( ctx->db, ret, "Maildir error: db->cursor()" ); else { for (;;) { if ((ret = dbc->c_get( dbc, &key, &value, DB_NEXT ))) { if (ret != DB_NOTFOUND) ctx->db->err( ctx->db, ret, "Maildir error: db->c_get()" ); break; } if (!equals( key.data, (int)key.size, "UIDVALIDITY", 11 ) && (ret = tdb->get( tdb, NULL, &key, &value, 0 ))) { if (ret != DB_NOTFOUND) { tdb->err( tdb, ret, "Maildir error: tdb->get()" ); break; } if ((ret = dbc->c_del( dbc, 0 ))) { ctx->db->err( ctx->db, ret, "Maildir error: db->c_del()" ); break; } } } dbc->c_close( dbc ); } tdb->close( tdb, 0 ); } #endif /* USE_DB */ qsort( msglist->array.data, msglist->array.size, sizeof(msg_t), maildir_compare ); for (uid = i = 0; i < msglist->array.size; i++) { entry = &msglist->array.data[i]; if (entry->uid != UINT_MAX) { if (uid == entry->uid) { #if 1 /* See comment in maildir_uidval_lock() why this is fatal. */ error( "Maildir error: duplicate UID %u.\n", uid ); maildir_free_scan( msglist ); return DRV_BOX_BAD; #else notice( "Maildir notice: duplicate UID; changing UIDVALIDITY.\n"); if ((ret = maildir_init_uid( ctx )) != DRV_OK) { maildir_free_scan( msglist ); return ret; } maildir_free_scan( msglist ); goto again; #endif } uid = entry->uid; if (uid > ctx->nuid) { /* In principle, we could just warn and top up nuid. However, getting into this * situation might indicate some serious trouble, so let's not make it worse. */ error( "Maildir error: UID %u is beyond highest assigned UID %u.\n", uid, ctx->nuid ); maildir_free_scan( msglist ); return DRV_BOX_BAD; } fnl = 0; #ifdef USE_DB } else if (ctx->usedb) { if ((ret = maildir_set_uid( ctx, entry->base, &uid )) != DRV_OK) { maildir_free_scan( msglist ); return ret; } entry->uid = uid; fnl = 0; #endif /* USE_DB */ } else { if ((ret = maildir_obtain_uid( ctx, &uid )) != DRV_OK) { maildir_free_scan( msglist ); return ret; } entry->uid = uid; if ((u = strstr( entry->base, ",U=" ))) for (ru = u + 3; isdigit( (uchar)*ru ); ru++); else u = ru = strchr( entry->base, conf->info_delimiter ); fnl = (u ? nfsnprintf( buf + bl, _POSIX_PATH_MAX - bl, "%s/%.*s,U=%u%s", subdirs[entry->recent], (int)(u - entry->base), entry->base, uid, ru ) : nfsnprintf( buf + bl, _POSIX_PATH_MAX - bl, "%s/%s,U=%u", subdirs[entry->recent], entry->base, uid )) - 4; memcpy( nbuf, buf, (size_t)(bl + 4) ); nfsnprintf( nbuf + bl + 4, _POSIX_PATH_MAX - bl - 4, "%s", entry->base ); if (rename( nbuf, buf )) { if (errno != ENOENT) { sys_error( "Maildir error: cannot rename %s to %s", nbuf, buf ); fail: maildir_free_scan( msglist ); return DRV_BOX_BAD; } retry: maildir_free_scan( msglist ); goto again; } free( entry->base ); entry->base = nfstrndup( buf + bl + 4, (size_t)fnl ); } int want_size = ((ctx->opts & OPEN_NEW_SIZE) && uid > ctx->newuid); int want_tuid = ((ctx->opts & OPEN_FIND) && uid >= ctx->finduid); int want_msgid = ((ctx->opts & OPEN_OLD_IDS) && uid <= ctx->pairuid); if (!want_size && !want_tuid && !want_msgid) continue; if (!fnl) nfsnprintf( buf + bl, _POSIX_PATH_MAX - bl, "%s/%s", subdirs[entry->recent], entry->base ); if (want_size) { if (stat( buf, &st )) { if (errno != ENOENT) { sys_error( "Maildir error: cannot stat %s", buf ); goto fail; } goto retry; } // The clipped value is good enough for MaxSize comparisons. entry->size = st.st_size > UINT_MAX ? UINT_MAX : (uint)st.st_size; } if (want_tuid || want_msgid) { if (!(f = fopen( buf, "r" ))) { if (errno != ENOENT) { sys_error( "Maildir error: cannot open %s", buf ); goto fail; } goto retry; } int off, in_msgid = 0; char lnbuf[1000]; // Says RFC2822 while ((want_tuid || want_msgid) && fgets( lnbuf, sizeof(lnbuf), f )) { int bufl = strlen( lnbuf ); if (bufl && lnbuf[bufl - 1] == '\n') --bufl; if (bufl && lnbuf[bufl - 1] == '\r') --bufl; if (!bufl) break; if (want_tuid && starts_with( lnbuf, bufl, "X-TUID: ", 8 )) { if (bufl < 8 + TUIDL) { error( "Maildir error: malformed X-TUID header (UID %u)\n", uid ); continue; } memcpy( entry->tuid, lnbuf + 8, TUIDL ); want_tuid = 0; in_msgid = 0; continue; } if (want_msgid && starts_with_upper( lnbuf, bufl, "MESSAGE-ID:", 11 )) { off = 11; } else if (in_msgid) { if (!isspace( lnbuf[0] )) { in_msgid = 0; continue; } off = 1; } else { continue; } while (off < bufl && isspace( lnbuf[off] )) off++; if (off == bufl) { in_msgid = 1; continue; } entry->msgid = nfstrndup( lnbuf + off, (size_t)(bufl - off) ); want_msgid = 0; in_msgid = 0; } fclose( f ); } } ctx->uvok = 1; } return DRV_OK; } static void maildir_init_msg( maildir_store_t *ctx, maildir_message_t *msg, msg_t *entry ) { msg->base = entry->base; entry->base = NULL; /* prevent deletion */ msg->msgid = entry->msgid; entry->msgid = NULL; /* prevent deletion */ msg->size = entry->size; msg->srec = NULL; memcpy( msg->tuid, entry->tuid, TUIDL ); if (entry->recent) msg->status |= M_RECENT; if (ctx->opts & OPEN_FLAGS) { msg->status |= M_FLAGS; msg->flags = maildir_parse_flags( ctx->conf->info_prefix, msg->base ); } else msg->flags = 0; } static void maildir_app_msg( maildir_store_t *ctx, maildir_message_t ***msgapp, msg_t *entry ) { maildir_message_t *msg = nfmalloc( sizeof(*msg) ); msg->next = **msgapp; **msgapp = msg; *msgapp = &msg->next; msg->uid = entry->uid; msg->status = 0; maildir_init_msg( ctx, msg, entry ); } static int maildir_select_box( store_t *gctx, const char *name ) { maildir_store_t *ctx = (maildir_store_t *)gctx; maildir_store_conf_t *conf = ctx->conf; maildir_cleanup( gctx ); ctx->msgs = NULL; ctx->excs.data = NULL; ctx->uvfd = -1; #ifdef USE_DB ctx->db = NULL; ctx->usedb = NULL; #endif /* USE_DB */ ctx->fresh[0] = ctx->fresh[1] = 0; if (starts_with( name, -1, "INBOX", 5 ) && (!name[5] || name[5] == '/')) { if (!name[5]) { ctx->path = nfstrdup( conf->inbox ); ctx->is_inbox = 1; } else { ctx->path = maildir_join_path( conf, 1, name + 5 ); ctx->is_inbox = 0; } } else { if (!(ctx->path = maildir_join_path( conf, 0, name ))) return DRV_STORE_BAD; ctx->is_inbox = 0; } return ctx->path ? DRV_OK : DRV_BOX_BAD; } static const char * maildir_get_box_path( store_t *gctx ) { return ((maildir_store_t *)gctx)->path; } static void maildir_open_box( store_t *gctx, void (*cb)( int sts, uint uidvalidity, void *aux ), void *aux ) { maildir_store_t *ctx = (maildir_store_t *)gctx; int ret; char uvpath[_POSIX_PATH_MAX]; if ((ret = maildir_validate( ctx->path, ctx->is_inbox, ctx )) != DRV_OK) goto bail; nfsnprintf( uvpath, sizeof(uvpath), "%s/.uidvalidity", ctx->path ); #ifndef USE_DB if ((ctx->uvfd = open( uvpath, O_RDWR|O_CREAT, 0600 )) < 0) { sys_error( "Maildir error: cannot write %s", uvpath ); cb( DRV_BOX_BAD, UIDVAL_BAD, aux ); return; } #else ctx->usedb = NULL; if ((ctx->uvfd = open( uvpath, O_RDWR, 0600 )) < 0) { nfsnprintf( uvpath, sizeof(uvpath), "%s/.isyncuidmap.db", ctx->path ); if ((ctx->uvfd = open( uvpath, O_RDWR, 0600 )) < 0) { if (ctx->conf->alt_map) { if ((ctx->uvfd = open( uvpath, O_RDWR|O_CREAT, 0600 )) >= 0) goto dbok; } else { nfsnprintf( uvpath, sizeof(uvpath), "%s/.uidvalidity", ctx->path ); if ((ctx->uvfd = open( uvpath, O_RDWR|O_CREAT, 0600 )) >= 0) goto fnok; } sys_error( "Maildir error: cannot write %s", uvpath ); cb( DRV_BOX_BAD, UIDVAL_BAD, aux ); return; } else { dbok: ctx->usedb = nfstrdup( uvpath ); } } fnok: #endif /* USE_DB */ ret = maildir_uidval_lock( ctx ); bail: cb( ret, ctx->uidvalidity, aux ); } static uint maildir_get_uidnext( store_t *gctx ) { maildir_store_t *ctx = (maildir_store_t *)gctx; return ctx->nuid; } static xint maildir_get_supported_flags( store_t *gctx ATTR_UNUSED ) { return 255; } static void maildir_create_box( store_t *gctx, void (*cb)( int sts, void *aux ), void *aux ) { maildir_store_t *ctx = (maildir_store_t *)gctx; cb( maildir_validate( ctx->path, 1, ctx ), aux ); } static int maildir_confirm_box_empty( store_t *gctx ) { maildir_store_t *ctx = (maildir_store_t *)gctx; msg_t_array_alloc_t msglist; ctx->excs.size = ctx->minuid = ctx->maxuid = ctx->finduid = 0; if (maildir_scan( ctx, &msglist ) != DRV_OK) return DRV_BOX_BAD; maildir_free_scan( &msglist ); return ctx->total_msgs ? DRV_BOX_BAD : DRV_OK; } static void maildir_delete_box( store_t *gctx, void (*cb)( int sts, void *aux ), void *aux ) { maildir_store_t *ctx = (maildir_store_t *)gctx; int i, bl, ret = DRV_OK; struct stat st; char buf[_POSIX_PATH_MAX]; bl = nfsnprintf( buf, sizeof(buf) - 4, "%s/", ctx->path ); if (stat( buf, &st )) { if (errno != ENOENT) { sys_error( "Maildir error: cannot access mailbox '%s'", ctx->path ); ret = DRV_BOX_BAD; } } else if (!S_ISDIR(st.st_mode)) { error( "Maildir error: '%s' is no valid mailbox\n", ctx->path ); ret = DRV_BOX_BAD; } else if ((ret = maildir_clear_tmp( buf, sizeof(buf), bl )) == DRV_OK) { nfsnprintf( buf + bl, _POSIX_PATH_MAX - bl, ".uidvalidity" ); if (unlink( buf ) && errno != ENOENT) goto badrm; #ifdef USE_DB nfsnprintf( buf + bl, _POSIX_PATH_MAX - bl, ".isyncuidmap.db" ); if (unlink( buf ) && errno != ENOENT) goto badrm; #endif /* We delete cur/ last, as it is the indicator for a present mailbox. * That way an interrupted operation can be resumed. */ for (i = 3; --i >= 0; ) { memcpy( buf + bl, subdirs[i], 4 ); if (rmdir( buf ) && errno != ENOENT) { badrm: sys_error( "Maildir error: cannot remove '%s'", buf ); ret = DRV_BOX_BAD; break; } } } cb( ret, aux ); } static int maildir_finish_delete_box( store_t *gctx ) { maildir_store_t *ctx = (maildir_store_t *)gctx; /* Subfolders are not deleted; the deleted folder is only "stripped of its mailboxness". * Consequently, the rmdir may legitimately fail. This behavior follows the IMAP spec. */ if (rmdir( ctx->path ) && errno != ENOENT && errno != ENOTEMPTY) { sys_error( "Maildir warning: cannot remove '%s'", ctx->path ); return DRV_BOX_BAD; } return DRV_OK; } static uint maildir_prepare_load_box( store_t *gctx, uint opts ) { maildir_store_t *ctx = (maildir_store_t *)gctx; if (opts & OPEN_SETFLAGS) opts |= OPEN_OLD; if (opts & OPEN_EXPUNGE) opts |= OPEN_OLD|OPEN_NEW|OPEN_FLAGS; ctx->opts = opts; return opts; } static void maildir_load_box( store_t *gctx, uint minuid, uint maxuid, uint finduid, uint pairuid, uint newuid, uint_array_t excs, void (*cb)( int sts, message_t *msgs, int total_msgs, int recent_msgs, void *aux ), void *aux ) { maildir_store_t *ctx = (maildir_store_t *)gctx; maildir_message_t **msgapp; msg_t_array_alloc_t msglist; uint i; ctx->minuid = minuid; ctx->maxuid = maxuid; ctx->finduid = finduid; ctx->pairuid = pairuid; ctx->newuid = newuid; ARRAY_SQUEEZE( &excs ); ctx->excs = excs; if (maildir_scan( ctx, &msglist ) != DRV_OK) { cb( DRV_BOX_BAD, NULL, 0, 0, aux ); return; } msgapp = &ctx->msgs; for (i = 0; i < msglist.array.size; i++) maildir_app_msg( ctx, &msgapp, msglist.array.data + i ); maildir_free_scan( &msglist ); cb( DRV_OK, &ctx->msgs->gen, ctx->total_msgs, ctx->recent_msgs, aux ); } static int maildir_rescan( maildir_store_t *ctx ) { maildir_message_t **msgapp, *msg; msg_t_array_alloc_t msglist; uint i; ctx->fresh[0] = ctx->fresh[1] = 0; if (maildir_scan( ctx, &msglist ) != DRV_OK) return DRV_BOX_BAD; for (msgapp = &ctx->msgs, i = 0; (msg = *msgapp) || i < msglist.array.size; ) { if (!msg) { #if 0 debug( "adding new message %u\n", msglist.array.data[i].uid ); maildir_app_msg( ctx, &msgapp, msglist.array.data + i ); #else debug( "ignoring new message %u\n", msglist.array.data[i].uid ); #endif i++; } else if (i >= msglist.array.size) { debug( "purging deleted message %u\n", msg->uid ); msg->status = M_DEAD; msgapp = &msg->next; } else if (msglist.array.data[i].uid < msg->uid) { /* this should not happen, actually */ #if 0 debug( "adding new message %u\n", msglist.array.data[i].uid ); maildir_app_msg( ctx, &msgapp, msglist.array.data + i ); #else debug( "ignoring new message %u\n", msglist.array.data[i].uid ); #endif i++; } else if (msglist.array.data[i].uid > msg->uid) { debug( "purging deleted message %u\n", msg->uid ); msg->status = M_DEAD; msgapp = &msg->next; } else { debug( "updating message %u\n", msg->uid ); msg->status &= ~(M_FLAGS|M_RECENT); free( msg->base ); free( msg->msgid ); maildir_init_msg( ctx, msg, msglist.array.data + i ); i++, msgapp = &msg->next; } } maildir_free_scan( &msglist ); return DRV_OK; } static int ATTR_PRINTFLIKE(3, 0) maildir_again( maildir_store_t *ctx, maildir_message_t *msg, const char *err, ... ) { int ret; if (errno != ENOENT) { va_list va; va_start( va, err ); vsys_error( err, va ); va_end( va ); return DRV_BOX_BAD; } if ((ret = maildir_rescan( ctx )) != DRV_OK) return ret; return (msg->status & M_DEAD) ? DRV_MSG_BAD : DRV_OK; } static void maildir_fetch_msg( store_t *gctx, message_t *gmsg, msg_data_t *data, int minimal ATTR_UNUSED, void (*cb)( int sts, void *aux ), void *aux ) { maildir_store_t *ctx = (maildir_store_t *)gctx; maildir_message_t *msg = (maildir_message_t *)gmsg; int fd, ret; struct stat st; char buf[_POSIX_PATH_MAX]; for (;;) { nfsnprintf( buf, sizeof(buf), "%s/%s/%s", ctx->path, subdirs[gmsg->status & M_RECENT], msg->base ); if ((fd = open( buf, O_RDONLY )) >= 0) break; if ((ret = maildir_again( ctx, msg, "Cannot open %s", buf )) != DRV_OK) { cb( ret, aux ); return; } } fstat( fd, &st ); if (st.st_size > INT_MAX) { error( "Maildir error: %s is too big", buf ); goto mbad; } data->len = st.st_size; if (data->date == -1) data->date = st.st_mtime; data->data = nfmalloc( data->len ); if (read( fd, data->data, data->len ) != data->len) { sys_error( "Maildir error: cannot read %s", buf ); mbad: close( fd ); cb( DRV_MSG_BAD, aux ); return; } close( fd ); if (!(gmsg->status & M_FLAGS)) data->flags = maildir_parse_flags( ctx->conf->info_prefix, msg->base ); cb( DRV_OK, aux ); } static int maildir_make_flags( char info_delimiter, uchar flags, char *buf ) { int i, d; buf[0] = info_delimiter; buf[1] = '2'; buf[2] = ','; for (d = 3, i = 0; i < (int)as(Flags); i++) if (flags & (1 << i)) buf[d++] = Flags[i]; buf[d] = 0; return d; } static void maildir_store_msg( store_t *gctx, msg_data_t *data, int to_trash, void (*cb)( int sts, uint uid, void *aux ), void *aux ) { maildir_store_t *ctx = (maildir_store_t *)gctx; const char *box; int ret, fd, bl; uint uid; char buf[_POSIX_PATH_MAX], nbuf[_POSIX_PATH_MAX], fbuf[NUM_FLAGS + 3], base[128]; bl = nfsnprintf( base, sizeof(base), "%lld.%d_%d.%s", (long long)time( NULL ), Pid, ++MaildirCount, Hostname ); if (!to_trash) { #ifdef USE_DB if (ctx->usedb) { if ((ret = maildir_set_uid( ctx, base, &uid )) != DRV_OK) { free( data->data ); cb( ret, 0, aux ); return; } } else #endif /* USE_DB */ { if ((ret = maildir_obtain_uid( ctx, &uid )) != DRV_OK) { free( data->data ); cb( ret, 0, aux ); return; } nfsnprintf( base + bl, (int)sizeof(base) - bl, ",U=%u", uid ); } box = ctx->path; } else { uid = 0; box = ctx->trash; } maildir_make_flags( ctx->conf->info_delimiter, data->flags, fbuf ); nfsnprintf( buf, sizeof(buf), "%s/tmp/%s%s", box, base, fbuf ); if ((fd = open( buf, O_WRONLY|O_CREAT|O_EXCL, 0600 )) < 0) { if (errno != ENOENT || !to_trash) { sys_error( "Maildir error: cannot create %s", buf ); free( data->data ); cb( DRV_BOX_BAD, 0, aux ); return; } if ((ret = maildir_validate( box, 1, ctx )) != DRV_OK) { free( data->data ); cb( ret, 0, aux ); return; } if ((fd = open( buf, O_WRONLY|O_CREAT|O_EXCL, 0600 )) < 0) { sys_error( "Maildir error: cannot create %s", buf ); free( data->data ); cb( DRV_BOX_BAD, 0, aux ); return; } } ret = write( fd, data->data, data->len ); free( data->data ); if (ret != (int)data->len || (UseFSync && (ret = fsync( fd )))) { if (ret < 0) sys_error( "Maildir error: cannot write %s", buf ); else error( "Maildir error: cannot write %s. Disk full?\n", buf ); close( fd ); cb( DRV_BOX_BAD, 0, aux ); return; } if (close( fd ) < 0) { /* Quota exceeded may cause this. */ sys_error( "Maildir error: cannot write %s", buf ); cb( DRV_BOX_BAD, 0, aux ); return; } if (data->date) { /* Set atime and mtime according to INTERNALDATE or mtime of source message */ struct utimbuf utimebuf; utimebuf.actime = utimebuf.modtime = data->date; if (utime( buf, &utimebuf ) < 0) { sys_error( "Maildir error: cannot set times for %s", buf ); cb( DRV_BOX_BAD, 0, aux ); return; } } /* Moving seen messages to cur/ is strictly speaking incorrect, but makes mutt happy. */ nfsnprintf( nbuf, sizeof(nbuf), "%s/%s/%s%s", box, subdirs[!(data->flags & F_SEEN)], base, fbuf ); if (rename( buf, nbuf )) { sys_error( "Maildir error: cannot rename %s to %s", buf, nbuf ); cb( DRV_BOX_BAD, 0, aux ); return; } cb( DRV_OK, uid, aux ); } static void maildir_set_msg_flags( store_t *gctx, message_t *gmsg, uint uid ATTR_UNUSED, int add, int del, void (*cb)( int sts, void *aux ), void *aux ) { maildir_store_t *ctx = (maildir_store_t *)gctx; maildir_store_conf_t *conf = ctx->conf; maildir_message_t *msg = (maildir_message_t *)gmsg; char *s, *p; uint i; int j, ret, ol, fl, bbl, bl, tl; char buf[_POSIX_PATH_MAX], nbuf[_POSIX_PATH_MAX]; bbl = nfsnprintf( buf, sizeof(buf), "%s/", ctx->path ); memcpy( nbuf, ctx->path, (size_t)bbl - 1 ); memcpy( nbuf + bbl - 1, "/cur/", 5 ); for (;;) { bl = bbl + nfsnprintf( buf + bbl, _POSIX_PATH_MAX - bbl, "%s/", subdirs[gmsg->status & M_RECENT] ); ol = strlen( msg->base ); if (_POSIX_PATH_MAX - bl < ol + 3 + NUM_FLAGS) oob(); memcpy( buf + bl, msg->base, (size_t)ol + 1 ); memcpy( nbuf + bl, msg->base, (size_t)ol + 1 ); if ((s = strstr( nbuf + bl, conf->info_prefix ))) { s += 3; fl = ol - (s - (nbuf + bl)); for (i = 0; i < as(Flags); i++) { if ((p = strchr( s, Flags[i] ))) { if (del & (1 << i)) { memmove( p, p + 1, (size_t)fl - (size_t)(p - s) ); fl--; } } else if (add & (1 << i)) { for (j = 0; j < fl && Flags[i] > s[j]; j++); fl++; memmove( s + j + 1, s + j, (size_t)(fl - j) ); s[j] = Flags[i]; } } tl = ol + 3 + fl; } else { tl = ol + maildir_make_flags( conf->info_delimiter, (uchar)add, nbuf + bl + ol ); } if (!rename( buf, nbuf )) break; if ((ret = maildir_again( ctx, msg, "Maildir error: cannot rename %s to %s", buf, nbuf )) != DRV_OK) { cb( ret, aux ); return; } } free( msg->base ); msg->base = nfstrndup( nbuf + bl, (size_t)tl ); msg->flags |= add; msg->flags &= ~del; gmsg->status &= ~M_RECENT; cb( DRV_OK, aux ); } #ifdef USE_DB static int maildir_purge_msg( maildir_store_t *ctx, const char *name ) { int ret; if ((ret = maildir_uidval_lock( ctx )) != DRV_OK) return ret; make_key( ctx->conf->info_stop, &key, name ); if ((ret = ctx->db->del( ctx->db, NULL, &key, 0 ))) { ctx->db->err( ctx->db, ret, "Maildir error: db->del()" ); return DRV_BOX_BAD; } return DRV_OK; } #endif /* USE_DB */ static void maildir_trash_msg( store_t *gctx, message_t *gmsg, void (*cb)( int sts, void *aux ), void *aux ) { maildir_store_t *ctx = (maildir_store_t *)gctx; maildir_message_t *msg = (maildir_message_t *)gmsg; char *s; int ret; struct stat st; char buf[_POSIX_PATH_MAX], nbuf[_POSIX_PATH_MAX]; for (;;) { nfsnprintf( buf, sizeof(buf), "%s/%s/%s", ctx->path, subdirs[gmsg->status & M_RECENT], msg->base ); s = strstr( msg->base, ctx->conf->info_prefix ); nfsnprintf( nbuf, sizeof(nbuf), "%s/%s/%lld.%d_%d.%s%s", ctx->trash, subdirs[gmsg->status & M_RECENT], (long long)time( NULL ), Pid, ++MaildirCount, Hostname, s ? s : "" ); if (!rename( buf, nbuf )) break; if (!stat( buf, &st )) { if ((ret = maildir_validate( ctx->trash, 1, ctx )) != DRV_OK) { cb( ret, aux ); return; } if (!rename( buf, nbuf )) break; if (errno != ENOENT) { sys_error( "Maildir error: cannot move %s to %s", buf, nbuf ); cb( DRV_BOX_BAD, aux ); return; } } if ((ret = maildir_again( ctx, msg, "Maildir error: cannot move %s to %s", buf, nbuf )) != DRV_OK) { cb( ret, aux ); return; } } gmsg->status |= M_DEAD; ctx->total_msgs--; #ifdef USE_DB if (ctx->usedb) { cb( maildir_purge_msg( ctx, msg->base ), aux ); return; } #endif /* USE_DB */ cb( DRV_OK, aux ); } static void maildir_close_box( store_t *gctx, void (*cb)( int sts, void *aux ), void *aux ) { maildir_store_t *ctx = (maildir_store_t *)gctx; maildir_message_t *msg; int basel, retry, ret; char buf[_POSIX_PATH_MAX]; for (;;) { retry = 0; basel = nfsnprintf( buf, sizeof(buf), "%s/", ctx->path ); for (msg = ctx->msgs; msg; msg = msg->next) if (!(msg->status & M_DEAD) && (msg->flags & F_DELETED)) { nfsnprintf( buf + basel, _POSIX_PATH_MAX - basel, "%s/%s", subdirs[msg->status & M_RECENT], msg->base ); if (unlink( buf )) { if (errno == ENOENT) retry = 1; else sys_error( "Maildir error: cannot remove %s", buf ); } else { msg->status |= M_DEAD; ctx->total_msgs--; #ifdef USE_DB if (ctx->db && (ret = maildir_purge_msg( ctx, msg->base )) != DRV_OK) { cb( ret, aux ); return; } #endif /* USE_DB */ } } if (!retry) { cb( DRV_OK, aux ); return; } if ((ret = maildir_rescan( (maildir_store_t *)gctx )) != DRV_OK) { cb( ret, aux ); return; } } } static void maildir_cancel_cmds( store_t *gctx ATTR_UNUSED, void (*cb)( void *aux ), void *aux ) { cb( aux ); } static void maildir_commit_cmds( store_t *gctx ) { (void) gctx; } static uint maildir_get_memory_usage( store_t *gctx ATTR_UNUSED ) { return 0; } static int maildir_get_fail_state( store_conf_t *gconf ) { return ((maildir_store_conf_t *)gconf)->failed; } static int maildir_parse_store( conffile_t *cfg, store_conf_t **storep ) { maildir_store_conf_t *store; if (strcasecmp( "MaildirStore", cfg->cmd )) return 0; store = nfcalloc( sizeof(*store) ); store->info_delimiter = FieldDelimiter; store->driver = &maildir_driver; store->name = nfstrdup( cfg->val ); while (getcline( cfg ) && cfg->cmd) if (!strcasecmp( "Inbox", cfg->cmd )) store->inbox = expand_strdup( cfg->val ); else if (!strcasecmp( "Path", cfg->cmd )) store->path = expand_strdup( cfg->val ); #ifdef USE_DB else if (!strcasecmp( "AltMap", cfg->cmd )) store->alt_map = parse_bool( cfg ); #endif /* USE_DB */ else if (!strcasecmp( "InfoDelimiter", cfg->cmd )) { if (strlen( cfg->val ) != 1) { error( "%s:%d: Info delimiter must be exactly one character long\n", cfg->file, cfg->line ); cfg->err = 1; continue; } store->info_delimiter = cfg->val[0]; if (!ispunct( store->info_delimiter )) { error( "%s:%d: Info delimiter must be a punctuation character\n", cfg->file, cfg->line ); cfg->err = 1; continue; } } else if (!strcasecmp( "SubFolders", cfg->cmd )) { if (!strcasecmp( "Verbatim", cfg->val )) { store->sub_style = SUB_VERBATIM; } else if (!strcasecmp( "Maildir++", cfg->val )) { store->sub_style = SUB_MAILDIRPP; } else if (!strcasecmp( "Legacy", cfg->val )) { store->sub_style = SUB_LEGACY; } else { error( "%s:%d: Unrecognized SubFolders style\n", cfg->file, cfg->line ); cfg->err = 1; } } else parse_generic_store( &store->gen, cfg, "MaildirStore" ); if (!store->inbox) store->inbox = expand_strdup( "~/Maildir" ); if (store->sub_style == SUB_MAILDIRPP && store->path) { error( "Maildir store '%s': Setting Path is incompatible with 'SubFolders Maildir++'\n", store->name ); cfg->err = 1; } nfasprintf( &store->info_prefix, "%c2,", store->info_delimiter ); nfasprintf( &store->info_stop, "%c,", store->info_delimiter ); *storep = &store->gen; return 1; } static uint maildir_get_caps( store_t *gctx ATTR_UNUSED ) { return 0; /* XXX DRV_CRLF? */ } struct driver maildir_driver = { maildir_get_caps, maildir_parse_store, maildir_cleanup_drv, maildir_alloc_store, maildir_set_bad_callback, maildir_connect_store, maildir_free_store, maildir_free_store, /* _cancel_, but it's the same */ maildir_list_store, maildir_select_box, maildir_get_box_path, maildir_create_box, maildir_open_box, maildir_get_uidnext, maildir_get_supported_flags, maildir_confirm_box_empty, maildir_delete_box, maildir_finish_delete_box, maildir_prepare_load_box, maildir_load_box, maildir_fetch_msg, maildir_store_msg, NULL, // find_new_msgs maildir_set_msg_flags, maildir_trash_msg, maildir_close_box, maildir_cancel_cmds, maildir_commit_cmds, maildir_get_memory_usage, maildir_get_fail_state, }; isync-1.4.4/INSTALL0000644000175000001440000003661414006611564010630 00000000000000Installation Instructions ************************* Copyright (C) 1994-1996, 1999-2002, 2004-2016 Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. This file is offered as-is, without warranty of any kind. Basic Installation ================== Briefly, the shell command './configure && make && make install' should configure, build, and install this package. The following more-detailed instructions are generic; see the 'README' file for instructions specific to this package. Some packages provide this 'INSTALL' file but do not implement all of the features documented below. The lack of an optional feature in a given package is not necessarily a bug. More recommendations for GNU packages can be found in *note Makefile Conventions: (standards)Makefile Conventions. The 'configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a 'Makefile' in each directory of the package. It may also create one or more '.h' files containing system-dependent definitions. Finally, it creates a shell script 'config.status' that you can run in the future to recreate the current configuration, and a file 'config.log' containing compiler output (useful mainly for debugging 'configure'). It can also use an optional file (typically called 'config.cache' and enabled with '--cache-file=config.cache' or simply '-C') that saves the results of its tests to speed up reconfiguring. Caching is disabled by default to prevent problems with accidental use of stale cache files. If you need to do unusual things to compile the package, please try to figure out how 'configure' could check whether to do them, and mail diffs or instructions to the address given in the 'README' so they can be considered for the next release. If you are using the cache, and at some point 'config.cache' contains results you don't want to keep, you may remove or edit it. The file 'configure.ac' (or 'configure.in') is used to create 'configure' by a program called 'autoconf'. You need 'configure.ac' if you want to change it or regenerate 'configure' using a newer version of 'autoconf'. The simplest way to compile this package is: 1. 'cd' to the directory containing the package's source code and type './configure' to configure the package for your system. Running 'configure' might take a while. While running, it prints some messages telling which features it is checking for. 2. Type 'make' to compile the package. 3. Optionally, type 'make check' to run any self-tests that come with the package, generally using the just-built uninstalled binaries. 4. Type 'make install' to install the programs and any data files and documentation. When installing into a prefix owned by root, it is recommended that the package be configured and built as a regular user, and only the 'make install' phase executed with root privileges. 5. Optionally, type 'make installcheck' to repeat any self-tests, but this time using the binaries in their final installed location. This target does not install anything. Running this target as a regular user, particularly if the prior 'make install' required root privileges, verifies that the installation completed correctly. 6. You can remove the program binaries and object files from the source code directory by typing 'make clean'. To also remove the files that 'configure' created (so you can compile the package for a different kind of computer), type 'make distclean'. There is also a 'make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. 7. Often, you can also type 'make uninstall' to remove the installed files again. In practice, not all packages have tested that uninstallation works correctly, even though it is required by the GNU Coding Standards. 8. Some packages, particularly those that use Automake, provide 'make distcheck', which can by used by developers to test that all other targets like 'make install' and 'make uninstall' work correctly. This target is generally not run by end users. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the 'configure' script does not know about. Run './configure --help' for details on some of the pertinent environment variables. You can give 'configure' initial values for configuration parameters by setting variables in the command line or in the environment. Here is an example: ./configure CC=c99 CFLAGS=-g LIBS=-lposix *Note Defining Variables::, for more details. Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you can use GNU 'make'. 'cd' to the directory where you want the object files and executables to go and run the 'configure' script. 'configure' automatically checks for the source code in the directory that 'configure' is in and in '..'. This is known as a "VPATH" build. With a non-GNU 'make', it is safer to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use 'make distclean' before reconfiguring for another architecture. On MacOS X 10.5 and later systems, you can create libraries and executables that work on multiple system types--known as "fat" or "universal" binaries--by specifying multiple '-arch' options to the compiler but only a single '-arch' option to the preprocessor. Like this: ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ CPP="gcc -E" CXXCPP="g++ -E" This is not guaranteed to produce working output in all cases, you may have to build one architecture at a time and combine the results using the 'lipo' tool if you have problems. Installation Names ================== By default, 'make install' installs the package's commands under '/usr/local/bin', include files under '/usr/local/include', etc. You can specify an installation prefix other than '/usr/local' by giving 'configure' the option '--prefix=PREFIX', where PREFIX must be an absolute file name. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you pass the option '--exec-prefix=PREFIX' to 'configure', the package uses PREFIX as the prefix for installing programs and libraries. Documentation and other data files still use the regular prefix. In addition, if you use an unusual directory layout you can give options like '--bindir=DIR' to specify different values for particular kinds of files. Run 'configure --help' for a list of the directories you can set and what kinds of files go in them. In general, the default for these options is expressed in terms of '${prefix}', so that specifying just '--prefix' will affect all of the other directory specifications that were not explicitly provided. The most portable way to affect installation locations is to pass the correct locations to 'configure'; however, many packages provide one or both of the following shortcuts of passing variable assignments to the 'make install' command line to change installation locations without having to reconfigure or recompile. The first method involves providing an override variable for each affected directory. For example, 'make install prefix=/alternate/directory' will choose an alternate location for all directory configuration variables that were expressed in terms of '${prefix}'. Any directories that were specified during 'configure', but not in terms of '${prefix}', must each be overridden at install time for the entire installation to be relocated. The approach of makefile variable overrides for each directory variable is required by the GNU Coding Standards, and ideally causes no recompilation. However, some platforms have known limitations with the semantics of shared libraries that end up requiring recompilation when using this method, particularly noticeable in packages that use GNU Libtool. The second method involves providing the 'DESTDIR' variable. For example, 'make install DESTDIR=/alternate/directory' will prepend '/alternate/directory' before all installation names. The approach of 'DESTDIR' overrides is not required by the GNU Coding Standards, and does not work on platforms that have drive letters. On the other hand, it does better at avoiding recompilation issues, and works well even when some directory options were not specified in terms of '${prefix}' at 'configure' time. Optional Features ================= If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving 'configure' the option '--program-prefix=PREFIX' or '--program-suffix=SUFFIX'. Some packages pay attention to '--enable-FEATURE' options to 'configure', where FEATURE indicates an optional part of the package. They may also pay attention to '--with-PACKAGE' options, where PACKAGE is something like 'gnu-as' or 'x' (for the X Window System). The 'README' should mention any '--enable-' and '--with-' options that the package recognizes. For packages that use the X Window System, 'configure' can usually find the X include and library files automatically, but if it doesn't, you can use the 'configure' options '--x-includes=DIR' and '--x-libraries=DIR' to specify their locations. Some packages offer the ability to configure how verbose the execution of 'make' will be. For these packages, running './configure --enable-silent-rules' sets the default to minimal output, which can be overridden with 'make V=1'; while running './configure --disable-silent-rules' sets the default to verbose, which can be overridden with 'make V=0'. Particular systems ================== On HP-UX, the default C compiler is not ANSI C compatible. If GNU CC is not installed, it is recommended to use the following options in order to use an ANSI C compiler: ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" and if that doesn't work, install pre-built binaries of GCC for HP-UX. HP-UX 'make' updates targets which have the same time stamps as their prerequisites, which makes it generally unusable when shipped generated files such as 'configure' are involved. Use GNU 'make' instead. On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot parse its '' header file. The option '-nodtk' can be used as a workaround. If GNU CC is not installed, it is therefore recommended to try ./configure CC="cc" and if that doesn't work, try ./configure CC="cc -nodtk" On Solaris, don't put '/usr/ucb' early in your 'PATH'. This directory contains several dysfunctional programs; working variants of these programs are available in '/usr/bin'. So, if you need '/usr/ucb' in your 'PATH', put it _after_ '/usr/bin'. On Haiku, software installed for all users goes in '/boot/common', not '/usr/local'. It is recommended to use the following options: ./configure --prefix=/boot/common Specifying the System Type ========================== There may be some features 'configure' cannot figure out automatically, but needs to determine by the type of machine the package will run on. Usually, assuming the package is built to be run on the _same_ architectures, 'configure' can figure that out, but if it prints a message saying it cannot guess the machine type, give it the '--build=TYPE' option. TYPE can either be a short name for the system type, such as 'sun4', or a canonical name which has the form: CPU-COMPANY-SYSTEM where SYSTEM can have one of these forms: OS KERNEL-OS See the file 'config.sub' for the possible values of each field. If 'config.sub' isn't included in this package, then this package doesn't need to know the machine type. If you are _building_ compiler tools for cross-compiling, you should use the option '--target=TYPE' to select the type of system they will produce code for. If you want to _use_ a cross compiler, that generates code for a platform different from the build platform, you should specify the "host" platform (i.e., that on which the generated programs will eventually be run) with '--host=TYPE'. Sharing Defaults ================ If you want to set default values for 'configure' scripts to share, you can create a site shell script called 'config.site' that gives default values for variables like 'CC', 'cache_file', and 'prefix'. 'configure' looks for 'PREFIX/share/config.site' if it exists, then 'PREFIX/etc/config.site' if it exists. Or, you can set the 'CONFIG_SITE' environment variable to the location of the site script. A warning: not all 'configure' scripts look for a site script. Defining Variables ================== Variables not defined in a site shell script can be set in the environment passed to 'configure'. However, some packages may run configure again during the build, and the customized values of these variables may be lost. In order to avoid this problem, you should set them in the 'configure' command line, using 'VAR=value'. For example: ./configure CC=/usr/local2/bin/gcc causes the specified 'gcc' to be used as the C compiler (unless it is overridden in the site shell script). Unfortunately, this technique does not work for 'CONFIG_SHELL' due to an Autoconf limitation. Until the limitation is lifted, you can use this workaround: CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash 'configure' Invocation ====================== 'configure' recognizes the following options to control how it operates. '--help' '-h' Print a summary of all of the options to 'configure', and exit. '--help=short' '--help=recursive' Print a summary of the options unique to this package's 'configure', and exit. The 'short' variant lists options used only in the top level, while the 'recursive' variant lists options also present in any nested packages. '--version' '-V' Print the version of Autoconf used to generate the 'configure' script, and exit. '--cache-file=FILE' Enable the cache: use and save the results of the tests in FILE, traditionally 'config.cache'. FILE defaults to '/dev/null' to disable caching. '--config-cache' '-C' Alias for '--cache-file=config.cache'. '--quiet' '--silent' '-q' Do not print messages saying which checks are being made. To suppress all normal output, redirect it to '/dev/null' (any error messages will still be shown). '--srcdir=DIR' Look for the package's source code in directory DIR. Usually 'configure' can determine that directory automatically. '--prefix=DIR' Use DIR as the installation prefix. *note Installation Names:: for more details, including other options available for fine-tuning the installation locations. '--no-create' '-n' Run the configure checks, but stop before creating any output files. 'configure' also accepts some other, not widely useful, options. Run 'configure --help' for more details. isync-1.4.4/README0000644000175000001440000000470414006611550010445 00000000000000 _ (_)___ _ _ _ __ ___ | / __| | | | '_ \ / __| | \__ \ |_| | | | | (__ |_|___/\__, |_| |_|\___| |___/ isync/mbsync - free (GPL) mailbox synchronization program http://isync.sf.net/ See AUTHORS for contact information. ``mbsync'' is a command line application which synchronizes mailboxes; currently Maildir and IMAP4 mailboxes are supported. New messages, message deletions and flag changes can be propagated both ways. ``mbsync'' is suitable for use in IMAP-disconnected mode. Synchronization is based on unique message identifiers (UIDs), so no identification conflicts can occur (unlike with some other mail synchronizers). Synchronization state is kept in one local text file per mailbox pair; these files are protected against concurrent ``mbsync'' processes. Mailboxes can be safely modified while ``mbsync'' operates. Multiple replicas of each mailbox can be maintained. isync is the project name, while mbsync is the current executable name; this change was necessary because of massive changes in the user interface. * Features * Fine-grained selection of synchronization operations to perform * Synchronizes single mailboxes or entire mailbox collections * Partial mirrors possible: keep only the latest messages locally * Trash functionality: backup messages before removing them * IMAP features: * Supports TLS/SSL via imaps: (port 993) and STARTTLS * Supports SASL for authentication * Pipelining for maximum speed * Compatibility isync should work fairly well with any IMAP4 compliant server; servers that support the UIDPLUS and LITERAL+ extensions are most efficient. Courier 1.4.3 is known to be buggy, version 1.7.3 works fine. M$ Exchange (2013 at least) needs DisableExtension MOVE to be compatible with the Trash functionality. * Platforms At some point, ``isync'' has successfully run on: Linux, Solaris 2.7, OpenBSD 2.8, FreeBSD 4.3. * Requirements perl v5.14+ Berkeley DB 4.1+ (optional) OpenSSL for TLS/SSL support (optional) Cyrus SASL (optional) zlib (optional) The build from git also requires: GNU autotools (autoconf & automake) perl module Date::Parse (libtimedate-perl on Debian, perl-TimeDate on Fedora and Suse) * Installation ./autogen.sh (only when building from git) ./configure make sudo make install * Help Please see the man page for complete documentation. isync-1.4.4/acinclude.m40000644000175000001440000000275214006611550011757 00000000000000# Add --enable-maintainer-mode option to configure. # From Jim Meyering # Change it to enable maintainer mode by default by Nicolas Boullis. # Copyright 1996, 1998, 2000, 2001, 2002 Free Software Foundation, Inc. # Copyright 2004 Nicolas Boullis. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation, # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA AC_DEFUN([AM_MAINTAINER_MODE], [AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles]) dnl maintainer-mode is enabled by default AC_ARG_ENABLE(maintainer-mode, [ --disable-maintainer-mode disable make rules and dependencies not useful (and sometimes confusing) to the casual installer], USE_MAINTAINER_MODE=$enableval, USE_MAINTAINER_MODE=yes) AC_MSG_RESULT([$USE_MAINTAINER_MODE]) AM_CONDITIONAL(MAINTAINER_MODE, [test $USE_MAINTAINER_MODE = yes]) MAINT=$MAINTAINER_MODE_TRUE AC_SUBST(MAINT)dnl ] ) isync-1.4.4/COPYING0000644000175000001440000004311014006611550010612 00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. isync-1.4.4/Makefile.in0000644000175000001440000007660314152373730011650 00000000000000# Makefile.in generated by automake 1.16.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2021 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@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) 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@ target_triplet = @target@ subdir = . ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \ $(am__configure_deps) $(am__DIST_COMMON) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno config.status.lineno mkinstalldirs = $(install_sh) -d CONFIG_HEADER = autodefs.h CONFIG_CLEAN_FILES = isync.spec CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(docdir)" SCRIPTS = $(bin_SCRIPTS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac DATA = $(doc_DATA) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ cscope distdir distdir-am dist dist-all distcheck am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) \ autodefs.h.in # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` DIST_SUBDIRS = $(SUBDIRS) am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/autodefs.h.in \ $(srcdir)/isync.spec.in AUTHORS COPYING ChangeLog INSTALL NEWS \ README TODO compile config.guess config.sub depcomp install-sh \ missing DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) am__remove_distdir = \ if test -d "$(distdir)"; then \ find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ && rm -rf "$(distdir)" \ || { sleep 5 && rm -rf "$(distdir)"; }; \ else :; fi am__post_remove_distdir = $(am__remove_distdir) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" DIST_ARCHIVES = $(distdir).tar.gz GZIP_ENV = --best DIST_TARGETS = dist-gzip # Exists only to be overridden by the user if desired. AM_DISTCHECK_DVI_TARGET = dvi distuninstallcheck_listfiles = find . -type f -print am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' distcleancheck_listfiles = find . -type f -print ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPPFLAGS = @CPPFLAGS@ CSCOPE = @CSCOPE@ CTAGS = @CTAGS@ CYGPATH_W = @CYGPATH_W@ DB_LIBS = @DB_LIBS@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ ETAGS = @ETAGS@ EXEEXT = @EXEEXT@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ KEYCHAIN_LIBS = @KEYCHAIN_LIBS@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ 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@ PERL = @PERL@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ SASL_LIBS = @SASL_LIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SOCK_LIBS = @SOCK_LIBS@ SSL_LIBS = @SSL_LIBS@ STRIP = @STRIP@ VERSION = @VERSION@ Z_LIBS = @Z_LIBS@ 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@ 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@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target = @target@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ SUBDIRS = src bin_SCRIPTS = mbsync-get-cert EXTRA_DIST = debian isync.spec $(bin_SCRIPTS) LOG_PL = \ use POSIX qw(strftime); \ use Date::Parse; \ use Text::Wrap; \ $$Text::Wrap::columns = 72; \ while (defined($$_ = <>)) { \ /^commit / or die "commit missing: $$_"; \ <> =~ /^log size (\d+)$$/ or die "wrong size"; \ $$len = $$1; \ read(STDIN, $$log, $$len) == $$len or die "unexpected EOF"; \ $$log =~ s/^Author: ([^>]+>)\nDate: (\d{4}-\d\d-\d\d \d\d:\d\d:\d\d [-+]\d{4})\n(.*)$$/$$3/s or die "unexpected log format"; \ $$author = $$1; $$date = str2time($$2); \ scalar(<>); \ @files = (); \ $$pfx = ""; \ while (defined($$l = <>) and $$l ne "\n") { \ chomp $$l; \ next if ($$l =~ m,^(ChangeLog$$|NEWS$$|TODO$$|debian/),); \ if (!@files) { \ $$pfx = $$l; \ $$pfx =~ s,/?[^/]+$$,,; \ } else { \ while (length($$pfx)) { \ $$l =~ m,^\Q$$pfx/\E, and last; \ $$pfx =~ s,/?[^/]+$$,,; \ } \ } \ push @files, $$l; \ } \ next if (!@files); \ print strftime("%F %H:%M", gmtime($$date))." ".$$author."\n\n"; \ if (@files > 1 and ($$len = length($$pfx))) { \ @efiles = (); \ for $$f (@files) { push @efiles, substr($$f, $$len + 1); } \ $$fstr = $$pfx."/: "; \ } else { \ @efiles = @files; \ $$fstr = ""; \ } \ print wrap("\t* ", "\t ", $$fstr.join(", ", @efiles).":")."\n"; \ $$log =~ s, +$$,,gm; \ $$log =~ s,^ ,\t,gm; \ print $$log."\n"; \ } doc_DATA = README TODO NEWS ChangeLog AUTHORS all: autodefs.h $(MAKE) $(AM_MAKEFLAGS) all-recursive .SUFFIXES: am--refresh: Makefile @: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ echo ' cd $(srcdir) && $(AUTOMAKE) --gnu'; \ $(am__cd) $(srcdir) && $(AUTOMAKE) --gnu \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ echo ' $(SHELL) ./config.status'; \ $(SHELL) ./config.status;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) $(SHELL) ./config.status --recheck $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) $(am__cd) $(srcdir) && $(AUTOCONF) $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) $(am__aclocal_m4_deps): autodefs.h: stamp-h1 @test -f $@ || rm -f stamp-h1 @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1 stamp-h1: $(srcdir)/autodefs.h.in $(top_builddir)/config.status @rm -f stamp-h1 cd $(top_builddir) && $(SHELL) ./config.status autodefs.h $(srcdir)/autodefs.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) rm -f stamp-h1 touch $@ distclean-hdr: -rm -f autodefs.h stamp-h1 isync.spec: $(top_builddir)/config.status $(srcdir)/isync.spec.in cd $(top_builddir) && $(SHELL) ./config.status $@ install-binSCRIPTS: $(bin_SCRIPTS) @$(NORMAL_INSTALL) @list='$(bin_SCRIPTS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(bin_SCRIPTS)'; test -n "$(bindir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(bindir)'; $(am__uninstall_files_from_dir) install-docDATA: $(doc_DATA) @$(NORMAL_INSTALL) @list='$(doc_DATA)'; test -n "$(docdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(docdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(docdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(docdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(docdir)" || exit $$?; \ done uninstall-docDATA: @$(NORMAL_UNINSTALL) @list='$(doc_DATA)'; test -n "$(docdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(docdir)'; $(am__uninstall_files_from_dir) # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscope: cscope.files test ! -s cscope.files \ || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS) clean-cscope: -rm -f cscope.files cscope.files: clean-cscope cscopelist cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags -rm -f cscope.out cscope.in.out cscope.po.out cscope.files distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) $(am__remove_distdir) test -d "$(distdir)" || mkdir "$(distdir)" @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 @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$(top_distdir)" distdir="$(distdir)" \ dist-hook -test -n "$(am__skip_mode_fix)" \ || find "$(distdir)" -type d ! -perm -755 \ -exec chmod u+rwx,go+rx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ || chmod -R a+r "$(distdir)" dist-gzip: distdir tardir=$(distdir) && $(am__tar) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).tar.gz $(am__post_remove_distdir) dist-bzip2: distdir tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 $(am__post_remove_distdir) dist-lzip: distdir tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz $(am__post_remove_distdir) dist-xz: distdir tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz $(am__post_remove_distdir) dist-zstd: distdir tardir=$(distdir) && $(am__tar) | zstd -c $${ZSTD_CLEVEL-$${ZSTD_OPT--19}} >$(distdir).tar.zst $(am__post_remove_distdir) dist-tarZ: distdir @echo WARNING: "Support for distribution archives compressed with" \ "legacy program 'compress' is deprecated." >&2 @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z $(am__post_remove_distdir) dist-shar: distdir @echo WARNING: "Support for shar distribution archives is" \ "deprecated." >&2 @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 shar $(distdir) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).shar.gz $(am__post_remove_distdir) dist-zip: distdir -rm -f $(distdir).zip zip -rq $(distdir).zip $(distdir) $(am__post_remove_distdir) dist dist-all: $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:' $(am__post_remove_distdir) # This target untars the dist file and tries a VPATH configuration. Then # it guarantees that the distribution is self-contained by making another # tarfile. distcheck: dist case '$(DIST_ARCHIVES)' in \ *.tar.gz*) \ eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).tar.gz | $(am__untar) ;;\ *.tar.bz2*) \ bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ *.tar.lz*) \ lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ *.tar.xz*) \ xz -dc $(distdir).tar.xz | $(am__untar) ;;\ *.tar.Z*) \ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ *.shar.gz*) \ eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\ *.zip*) \ unzip $(distdir).zip ;;\ *.tar.zst*) \ zstd -dc $(distdir).tar.zst | $(am__untar) ;;\ esac chmod -R a-w $(distdir) chmod u+w $(distdir) mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst chmod a-w $(distdir) test -d $(distdir)/_build || exit 0; \ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ && am__cwd=`pwd` \ && $(am__cd) $(distdir)/_build/sub \ && ../../configure \ $(AM_DISTCHECK_CONFIGURE_FLAGS) \ $(DISTCHECK_CONFIGURE_FLAGS) \ --srcdir=../.. --prefix="$$dc_install_base" \ && $(MAKE) $(AM_MAKEFLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) $(AM_DISTCHECK_DVI_TARGET) \ && $(MAKE) $(AM_MAKEFLAGS) check \ && $(MAKE) $(AM_MAKEFLAGS) install \ && $(MAKE) $(AM_MAKEFLAGS) installcheck \ && $(MAKE) $(AM_MAKEFLAGS) uninstall \ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ distuninstallcheck \ && chmod -R a-w "$$dc_install_base" \ && ({ \ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ } || { rm -rf "$$dc_destdir"; exit 1; }) \ && rm -rf "$$dc_destdir" \ && $(MAKE) $(AM_MAKEFLAGS) dist \ && rm -rf $(DIST_ARCHIVES) \ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ && cd "$$am__cwd" \ || exit 1 $(am__post_remove_distdir) @(echo "$(distdir) archives ready for distribution: "; \ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' distuninstallcheck: @test -n '$(distuninstallcheck_dir)' || { \ echo 'ERROR: trying to run $@ with an empty' \ '$$(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ $(am__cd) '$(distuninstallcheck_dir)' || { \ echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left after uninstall:" ; \ if test -n "$(DESTDIR)"; then \ echo " (check DESTDIR support)"; \ fi ; \ $(distuninstallcheck_listfiles) ; \ exit 1; } >&2 distcleancheck: distclean @if test '$(srcdir)' = . ; then \ echo "ERROR: distcleancheck can only run from a VPATH build" ; \ exit 1 ; \ fi @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left in build directory after distclean:" ; \ $(distcleancheck_listfiles) ; \ exit 1; } >&2 check-am: all-am check: check-recursive all-am: Makefile $(SCRIPTS) $(DATA) autodefs.h installdirs: installdirs-recursive installdirs-am: for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(docdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi 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-recursive clean-am: clean-generic mostlyclean-am distclean: distclean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -f Makefile distclean-am: clean-am distclean-generic distclean-hdr distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-docDATA install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-binSCRIPTS install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: uninstall-binSCRIPTS uninstall-docDATA .MAKE: $(am__recursive_targets) all install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ am--refresh check check-am clean clean-cscope clean-generic \ cscope cscopelist-am ctags ctags-am dist dist-all dist-bzip2 \ dist-gzip dist-hook dist-lzip dist-shar dist-tarZ dist-xz \ dist-zip dist-zstd distcheck distclean distclean-generic \ distclean-hdr distclean-tags distcleancheck distdir \ distuninstallcheck dvi dvi-am html html-am info info-am \ install install-am install-binSCRIPTS install-data \ install-data-am install-docDATA 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 installdirs-am \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-binSCRIPTS uninstall-docDATA .PRECIOUS: Makefile $(srcdir)/.git/index: $(srcdir)/ChangeLog: $(srcdir)/.git/index $(MAKE) log log: @test -z "$(srcdir)" || cd $(srcdir) && \ ( ! test -d .git || \ git log --pretty=medium --date=iso --log-size --name-only --no-merges | \ perl -e '$(LOG_PL)' > ChangeLog ) cov-scan: clean /opt/cov-analysis-*/bin/cov-build --dir cov-int $(MAKE) tar cavf isync-cov.tar.xz cov-int deb: CFLAGS= INSTALL= dpkg-buildpackage -b --no-sign dist-hook: find $(distdir)/debian \( -name .#\*# -o -type l \) -print0 | xargs -0r rm -rf -cd $(distdir)/debian && test -f .gitignore && rm -rf `cut -c2- .gitignore` .gitignore dist-sign: dist gpg -b -a $(PACKAGE)-$(VERSION).tar.gz rpm: dist CFLAGS="-O2 -mtune=core2" rpmbuild --clean -ta $(PACKAGE)-$(VERSION).tar.gz rpm-ia32: dist CFLAGS="-O2 -m32 -march=i686" rpmbuild --target i686-unknown-linux --clean -ta $(PACKAGE)-$(VERSION).tar.gz # 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: isync-1.4.4/AUTHORS0000644000175000001440000000076314006611550010636 00000000000000Oswald Buddenhagen * Contributor, current maintainer Theodore Ts'o * Contributor, Debian package co-maintainer Nicolas Boullis * Debian package maintainer and minor upstream contributions Michael Elkins * Original author Send questions and bug reports to the isync-devel@lists.sourceforge.net mailing list. _DON'T_ report bugs to Michael, not even in a CC: - he is not actively involved in isync development any more. isync-1.4.4/missing0000755000175000001440000001533614006611564011174 00000000000000#! /bin/sh # Common wrapper for a few potentially missing GNU programs. scriptversion=2018-03-07.03; # UTC # Copyright (C) 1996-2020 Free Software Foundation, Inc. # Originally written by Fran,cois Pinard , 1996. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. if test $# -eq 0; then echo 1>&2 "Try '$0 --help' for more information" exit 1 fi case $1 in --is-lightweight) # Used by our autoconf macros to check whether the available missing # script is modern enough. exit 0 ;; --run) # Back-compat with the calling convention used by older automake. shift ;; -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due to PROGRAM being missing or too old. Options: -h, --help display this help and exit -v, --version output version information and exit Supported PROGRAM values: aclocal autoconf autoheader autom4te automake makeinfo bison yacc flex lex help2man Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and 'g' are ignored when checking the name. Send bug reports to ." exit $? ;; -v|--v|--ve|--ver|--vers|--versi|--versio|--version) echo "missing $scriptversion (GNU Automake)" exit $? ;; -*) echo 1>&2 "$0: unknown '$1' option" echo 1>&2 "Try '$0 --help' for more information" exit 1 ;; esac # Run the given program, remember its exit status. "$@"; st=$? # If it succeeded, we are done. test $st -eq 0 && exit 0 # Also exit now if we it failed (or wasn't found), and '--version' was # passed; such an option is passed most likely to detect whether the # program is present and works. case $2 in --version|--help) exit $st;; esac # Exit code 63 means version mismatch. This often happens when the user # tries to use an ancient version of a tool on a file that requires a # minimum version. if test $st -eq 63; then msg="probably too old" elif test $st -eq 127; then # Program was missing. msg="missing on your system" else # Program was found and executed, but failed. Give up. exit $st fi perl_URL=https://www.perl.org/ flex_URL=https://github.com/westes/flex gnu_software_URL=https://www.gnu.org/software program_details () { case $1 in aclocal|automake) echo "The '$1' program is part of the GNU Automake package:" echo "<$gnu_software_URL/automake>" echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/autoconf>" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; autoconf|autom4te|autoheader) echo "The '$1' program is part of the GNU Autoconf package:" echo "<$gnu_software_URL/autoconf/>" echo "It also requires GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; esac } give_advice () { # Normalize program name to check for. normalized_program=`echo "$1" | sed ' s/^gnu-//; t s/^gnu//; t s/^g//; t'` printf '%s\n' "'$1' is $msg." configure_deps="'configure.ac' or m4 files included by 'configure.ac'" case $normalized_program in autoconf*) echo "You should only need it if you modified 'configure.ac'," echo "or m4 files included by it." program_details 'autoconf' ;; autoheader*) echo "You should only need it if you modified 'acconfig.h' or" echo "$configure_deps." program_details 'autoheader' ;; automake*) echo "You should only need it if you modified 'Makefile.am' or" echo "$configure_deps." program_details 'automake' ;; aclocal*) echo "You should only need it if you modified 'acinclude.m4' or" echo "$configure_deps." program_details 'aclocal' ;; autom4te*) echo "You might have modified some maintainer files that require" echo "the 'autom4te' program to be rebuilt." program_details 'autom4te' ;; bison*|yacc*) echo "You should only need it if you modified a '.y' file." echo "You may want to install the GNU Bison package:" echo "<$gnu_software_URL/bison/>" ;; lex*|flex*) echo "You should only need it if you modified a '.l' file." echo "You may want to install the Fast Lexical Analyzer package:" echo "<$flex_URL>" ;; help2man*) echo "You should only need it if you modified a dependency" \ "of a man page." echo "You may want to install the GNU Help2man package:" echo "<$gnu_software_URL/help2man/>" ;; makeinfo*) echo "You should only need it if you modified a '.texi' file, or" echo "any other file indirectly affecting the aspect of the manual." echo "You might want to install the Texinfo package:" echo "<$gnu_software_URL/texinfo/>" echo "The spurious makeinfo call might also be the consequence of" echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" echo "want to install GNU make:" echo "<$gnu_software_URL/make/>" ;; *) echo "You might have modified some files without having the proper" echo "tools for further handling them. Check the 'README' file, it" echo "often tells you about the needed prerequisites for installing" echo "this package. You may also peek at any GNU archive site, in" echo "case some other package contains this missing '$1' program." ;; esac } give_advice "$1" | sed -e '1s/^/WARNING: /' \ -e '2,$s/^/ /' >&2 # Propagate the correct exit status (expected to be 127 for a program # not found, 63 for a program that failed due to version mismatch). exit $st # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: isync-1.4.4/mbsync-get-cert0000755000175000001440000000351314006611550012513 00000000000000#!/bin/sh # # This script will extract the necessary certificate from the IMAP server # It assumes that an attacker isn't trying to spoof you when you connect # to the IMAP server! You're better off downloading the certificate # from a trusted source. # # Copyright (C) 2003 Theodore Ts'o # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation, # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA # if [ $# != 1 ]; then echo "Usage: $0 " >&2 exit 1 fi HOST=$1 seed=`date '+%s'` try=0 while :; do TMPDIR=/tmp/get-cert.$$.$seed mkdir $TMPDIR 2> /dev/null && break if [ $try = 1000 ]; then echo "Cannot create temporary directory." >&2 exit 1 fi try=`expr $try + 1` seed=`expr \( \( $seed \* 1103515245 \) + 12345 \) % 2147483648` done TMPFILE=$TMPDIR/get-cert ERRFILE=$TMPDIR/get-cert-err CERTFILE=$TMPDIR/cert echo QUIT | openssl s_client -connect $HOST:993 -showcerts \ > $TMPFILE 2> $ERRFILE sed -e '1,/^-----BEGIN CERTIFICATE-----/d' \ -e '/^-----END CERTIFICATE-----/,$d' < $TMPFILE > $CERTFILE if test -s $CERTFILE ; then echo -----BEGIN CERTIFICATE----- cat $CERTFILE echo -----END CERTIFICATE----- else echo "Couldn't retrieve certificate. openssl reported the following errors:" cat $ERRFILE fi rm -r $TMPDIR isync-1.4.4/config.guess0000755000175000001440000012637314006611564012121 00000000000000#! /bin/sh # Attempt to guess a canonical system name. # Copyright 1992-2018 Free Software Foundation, Inc. timestamp='2018-02-24' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # # Originally written by Per Bothner; maintained since 2000 by Ben Elliston. # # You can get the latest version of this script from: # https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess # # Please send patches to . me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Options: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright 1992-2018 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > "$dummy.c" ; for c in cc gcc c89 c99 ; do if ($c -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ; set_cc_for_build= ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown case "$UNAME_SYSTEM" in Linux|GNU|GNU/*) # If the system lacks a compiler, then just pick glibc. # We could probably try harder. LIBC=gnu eval "$set_cc_for_build" cat <<-EOF > "$dummy.c" #include #if defined(__UCLIBC__) LIBC=uclibc #elif defined(__dietlibc__) LIBC=dietlibc #else LIBC=gnu #endif EOF eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`" # If ldd exists, use it to detect musl libc. if command -v ldd >/dev/null && \ ldd --version 2>&1 | grep -q ^musl then LIBC=musl fi ;; esac # Note: order is significant - the case branches are not exclusive. case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ "/sbin/$sysctl" 2>/dev/null || \ "/usr/sbin/$sysctl" 2>/dev/null || \ echo unknown)` case "$UNAME_MACHINE_ARCH" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; earmv*) arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'` endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'` machine="${arch}${endian}"-unknown ;; *) machine="$UNAME_MACHINE_ARCH"-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently (or will in the future) and ABI. case "$UNAME_MACHINE_ARCH" in earm*) os=netbsdelf ;; arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval "$set_cc_for_build" if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # Determine ABI tags. case "$UNAME_MACHINE_ARCH" in earm*) expr='s/^earmv[0-9]/-eabi/;s/eb$//' abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"` ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "$UNAME_VERSION" in Debian*) release='-gnu' ;; *) release=`echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "$machine-${os}${release}${abi}" exit ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` echo "$UNAME_MACHINE_ARCH"-unknown-bitrig"$UNAME_RELEASE" exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo "$UNAME_MACHINE_ARCH"-unknown-openbsd"$UNAME_RELEASE" exit ;; *:LibertyBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` echo "$UNAME_MACHINE_ARCH"-unknown-libertybsd"$UNAME_RELEASE" exit ;; *:MidnightBSD:*:*) echo "$UNAME_MACHINE"-unknown-midnightbsd"$UNAME_RELEASE" exit ;; *:ekkoBSD:*:*) echo "$UNAME_MACHINE"-unknown-ekkobsd"$UNAME_RELEASE" exit ;; *:SolidBSD:*:*) echo "$UNAME_MACHINE"-unknown-solidbsd"$UNAME_RELEASE" exit ;; macppc:MirBSD:*:*) echo powerpc-unknown-mirbsd"$UNAME_RELEASE" exit ;; *:MirBSD:*:*) echo "$UNAME_MACHINE"-unknown-mirbsd"$UNAME_RELEASE" exit ;; *:Sortix:*:*) echo "$UNAME_MACHINE"-unknown-sortix exit ;; *:Redox:*:*) echo "$UNAME_MACHINE"-unknown-redox exit ;; mips:OSF1:*.*) echo mips-dec-osf1 exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE=alpha ;; "EV4.5 (21064)") UNAME_MACHINE=alpha ;; "LCA4 (21066/21068)") UNAME_MACHINE=alpha ;; "EV5 (21164)") UNAME_MACHINE=alphaev5 ;; "EV5.6 (21164A)") UNAME_MACHINE=alphaev56 ;; "EV5.6 (21164PC)") UNAME_MACHINE=alphapca56 ;; "EV5.7 (21164PC)") UNAME_MACHINE=alphapca57 ;; "EV6 (21264)") UNAME_MACHINE=alphaev6 ;; "EV6.7 (21264A)") UNAME_MACHINE=alphaev67 ;; "EV6.8CB (21264C)") UNAME_MACHINE=alphaev68 ;; "EV6.8AL (21264B)") UNAME_MACHINE=alphaev68 ;; "EV6.8CX (21264D)") UNAME_MACHINE=alphaev68 ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE=alphaev69 ;; "EV7 (21364)") UNAME_MACHINE=alphaev7 ;; "EV7.9 (21364A)") UNAME_MACHINE=alphaev79 ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo "$UNAME_MACHINE"-dec-osf"`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`" # Reset EXIT trap before exiting to avoid spurious non-zero exit code. exitcode=$? trap '' 0 exit $exitcode ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo "$UNAME_MACHINE"-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo "$UNAME_MACHINE"-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix"$UNAME_RELEASE" exit ;; arm*:riscos:*:*|arm*:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; s390x:SunOS:*:*) echo "$UNAME_MACHINE"-ibm-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`" exit ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`" exit ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) echo i386-pc-auroraux"$UNAME_RELEASE" exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) eval "$set_cc_for_build" SUN_ARCH=i386 # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if [ "$CC_FOR_BUILD" != no_compiler_found ]; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH=x86_64 fi fi echo "$SUN_ARCH"-pc-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" exit ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos"`echo "$UNAME_RELEASE"|sed -e 's/-/_/'`" exit ;; sun3*:SunOS:*:*) echo m68k-sun-sunos"$UNAME_RELEASE" exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos"$UNAME_RELEASE" ;; sun4) echo sparc-sun-sunos"$UNAME_RELEASE" ;; esac exit ;; aushp:SunOS:*:*) echo sparc-auspex-sunos"$UNAME_RELEASE" exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint"$UNAME_RELEASE" exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint"$UNAME_RELEASE" exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint"$UNAME_RELEASE" exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint"$UNAME_RELEASE" exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint"$UNAME_RELEASE" exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint"$UNAME_RELEASE" exit ;; m68k:machten:*:*) echo m68k-apple-machten"$UNAME_RELEASE" exit ;; powerpc:machten:*:*) echo powerpc-apple-machten"$UNAME_RELEASE" exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix"$UNAME_RELEASE" exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix"$UNAME_RELEASE" exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix"$UNAME_RELEASE" exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval "$set_cc_for_build" sed 's/^ //' << EOF > "$dummy.c" #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" && dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`"$dummy" "$dummyarg"` && { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos"$UNAME_RELEASE" exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ "$UNAME_PROCESSOR" = mc88100 ] || [ "$UNAME_PROCESSOR" = mc88110 ] then if [ "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx ] || \ [ "$TARGET_BINARY_INTERFACE"x = x ] then echo m88k-dg-dgux"$UNAME_RELEASE" else echo m88k-dg-dguxbcs"$UNAME_RELEASE" fi else echo i586-dg-dgux"$UNAME_RELEASE" fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) echo mips-sgi-irix"`echo "$UNAME_RELEASE"|sed -e 's/-/_/g'`" exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV="$UNAME_VERSION.$UNAME_RELEASE" fi echo "$UNAME_MACHINE"-ibm-aix"$IBM_REV" exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval "$set_cc_for_build" sed 's/^ //' << EOF > "$dummy.c" #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` then echo "$SYSTEM_NAME" else echo rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit ;; *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/lslpp ] ; then IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` else IBM_REV="$UNAME_VERSION.$UNAME_RELEASE" fi echo "$IBM_ARCH"-ibm-aix"$IBM_REV" exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd"$UNAME_RELEASE" # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'` case "$UNAME_MACHINE" in 9000/31?) HP_ARCH=m68000 ;; 9000/[34]??) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "$sc_cpu_version" in 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "$sc_kernel_bits" in 32) HP_ARCH=hppa2.0n ;; 64) HP_ARCH=hppa2.0w ;; '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 esac ;; esac fi if [ "$HP_ARCH" = "" ]; then eval "$set_cc_for_build" sed 's/^ //' << EOF > "$dummy.c" #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=`"$dummy"` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ "$HP_ARCH" = hppa2.0w ] then eval "$set_cc_for_build" # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH=hppa2.0w else HP_ARCH=hppa64 fi fi echo "$HP_ARCH"-hp-hpux"$HPUX_REV" exit ;; ia64:HP-UX:*:*) HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux"$HPUX_REV" exit ;; 3050*:HI-UX:*:*) eval "$set_cc_for_build" sed 's/^ //' << EOF > "$dummy.c" #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo "$UNAME_MACHINE"-unknown-osf1mk else echo "$UNAME_MACHINE"-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) echo t90-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo "$UNAME_MACHINE"-pc-bsdi"$UNAME_RELEASE" exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi"$UNAME_RELEASE" exit ;; *:BSD/OS:*:*) echo "$UNAME_MACHINE"-unknown-bsdi"$UNAME_RELEASE" exit ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`/usr/bin/uname -p` case "$UNAME_PROCESSOR" in amd64) UNAME_PROCESSOR=x86_64 ;; i386) UNAME_PROCESSOR=i586 ;; esac echo "$UNAME_PROCESSOR"-unknown-freebsd"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`" exit ;; i*:CYGWIN*:*) echo "$UNAME_MACHINE"-pc-cygwin exit ;; *:MINGW64*:*) echo "$UNAME_MACHINE"-pc-mingw64 exit ;; *:MINGW*:*) echo "$UNAME_MACHINE"-pc-mingw32 exit ;; *:MSYS*:*) echo "$UNAME_MACHINE"-pc-msys exit ;; i*:PW*:*) echo "$UNAME_MACHINE"-pc-pw32 exit ;; *:Interix*:*) case "$UNAME_MACHINE" in x86) echo i586-pc-interix"$UNAME_RELEASE" exit ;; authenticamd | genuineintel | EM64T) echo x86_64-unknown-interix"$UNAME_RELEASE" exit ;; IA64) echo ia64-unknown-interix"$UNAME_RELEASE" exit ;; esac ;; i*:UWIN*:*) echo "$UNAME_MACHINE"-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`" exit ;; *:GNU:*:*) # the GNU system echo "`echo "$UNAME_MACHINE"|sed -e 's,[-/].*$,,'`-unknown-$LIBC`echo "$UNAME_RELEASE"|sed -e 's,/.*$,,'`" exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo "$UNAME_MACHINE-unknown-`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`-$LIBC" exit ;; i*86:Minix:*:*) echo "$UNAME_MACHINE"-pc-minix exit ;; aarch64:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC=gnulibc1 ; fi echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; arc:Linux:*:* | arceb:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; arm*:Linux:*:*) eval "$set_cc_for_build" if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabi else echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabihf fi fi exit ;; avr32*:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; cris:Linux:*:*) echo "$UNAME_MACHINE"-axis-linux-"$LIBC" exit ;; crisv32:Linux:*:*) echo "$UNAME_MACHINE"-axis-linux-"$LIBC" exit ;; e2k:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; frv:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; hexagon:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; i*86:Linux:*:*) echo "$UNAME_MACHINE"-pc-linux-"$LIBC" exit ;; ia64:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; k1om:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; m32r*:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; m68*:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; mips:Linux:*:* | mips64:Linux:*:*) eval "$set_cc_for_build" sed 's/^ //' << EOF > "$dummy.c" #undef CPU #undef ${UNAME_MACHINE} #undef ${UNAME_MACHINE}el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=${UNAME_MACHINE}el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=${UNAME_MACHINE} #else CPU= #endif #endif EOF eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU'`" test "x$CPU" != x && { echo "$CPU-unknown-linux-$LIBC"; exit; } ;; mips64el:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; openrisc*:Linux:*:*) echo or1k-unknown-linux-"$LIBC" exit ;; or32:Linux:*:* | or1k*:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; padre:Linux:*:*) echo sparc-unknown-linux-"$LIBC" exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-"$LIBC" exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-"$LIBC" ;; PA8*) echo hppa2.0-unknown-linux-"$LIBC" ;; *) echo hppa-unknown-linux-"$LIBC" ;; esac exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-"$LIBC" exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-"$LIBC" exit ;; ppc64le:Linux:*:*) echo powerpc64le-unknown-linux-"$LIBC" exit ;; ppcle:Linux:*:*) echo powerpcle-unknown-linux-"$LIBC" exit ;; riscv32:Linux:*:* | riscv64:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo "$UNAME_MACHINE"-ibm-linux-"$LIBC" exit ;; sh64*:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; sh*:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; tile*:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; vax:Linux:*:*) echo "$UNAME_MACHINE"-dec-linux-"$LIBC" exit ;; x86_64:Linux:*:*) if objdump -f /bin/sh | grep -q elf32-x86-64; then echo "$UNAME_MACHINE"-pc-linux-"$LIBC"x32 else echo "$UNAME_MACHINE"-pc-linux-"$LIBC" fi exit ;; xtensa*:Linux:*:*) echo "$UNAME_MACHINE"-unknown-linux-"$LIBC" exit ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo "$UNAME_MACHINE"-pc-sysv4.2uw"$UNAME_VERSION" exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo "$UNAME_MACHINE"-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) echo "$UNAME_MACHINE"-unknown-stop exit ;; i*86:atheos:*:*) echo "$UNAME_MACHINE"-unknown-atheos exit ;; i*86:syllable:*:*) echo "$UNAME_MACHINE"-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) echo i386-unknown-lynxos"$UNAME_RELEASE" exit ;; i*86:*DOS:*:*) echo "$UNAME_MACHINE"-pc-msdosdjgpp exit ;; i*86:*:4.*:*) UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo "$UNAME_MACHINE"-univel-sysv"$UNAME_REL" else echo "$UNAME_MACHINE"-pc-sysv"$UNAME_REL" fi exit ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo "$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}{$UNAME_VERSION}" exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo "$UNAME_MACHINE"-pc-sco"$UNAME_REL" else echo "$UNAME_MACHINE"-pc-sysv32 fi exit ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configure will decide that # this is a cross-build. echo i586-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv"$UNAME_RELEASE" # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv"$UNAME_RELEASE" # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos"$UNAME_RELEASE" exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos"$UNAME_RELEASE" exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos"$UNAME_RELEASE" exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) echo powerpc-unknown-lynxos"$UNAME_RELEASE" exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv"$UNAME_RELEASE" exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo "$UNAME_MACHINE"-sni-sysv4 else echo ns32k-sni-sysv fi exit ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. echo "$UNAME_MACHINE"-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux"$UNAME_RELEASE" exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv"$UNAME_RELEASE" else echo mips-unknown-sysv"$UNAME_RELEASE" fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. echo i586-pc-haiku exit ;; x86_64:Haiku:*:*) echo x86_64-unknown-haiku exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux"$UNAME_RELEASE" exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux"$UNAME_RELEASE" exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux"$UNAME_RELEASE" exit ;; SX-7:SUPER-UX:*:*) echo sx7-nec-superux"$UNAME_RELEASE" exit ;; SX-8:SUPER-UX:*:*) echo sx8-nec-superux"$UNAME_RELEASE" exit ;; SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux"$UNAME_RELEASE" exit ;; SX-ACE:SUPER-UX:*:*) echo sxace-nec-superux"$UNAME_RELEASE" exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody"$UNAME_RELEASE" exit ;; *:Rhapsody:*:*) echo "$UNAME_MACHINE"-apple-rhapsody"$UNAME_RELEASE" exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown eval "$set_cc_for_build" if test "$UNAME_PROCESSOR" = unknown ; then UNAME_PROCESSOR=powerpc fi if test "`echo "$UNAME_RELEASE" | sed -e 's/\..*//'`" -le 10 ; then if [ "$CC_FOR_BUILD" != no_compiler_found ]; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then case $UNAME_PROCESSOR in i386) UNAME_PROCESSOR=x86_64 ;; powerpc) UNAME_PROCESSOR=powerpc64 ;; esac fi # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_PPC >/dev/null then UNAME_PROCESSOR=powerpc fi fi elif test "$UNAME_PROCESSOR" = i386 ; then # Avoid executing cc on OS X 10.9, as it ships with a stub # that puts up a graphical alert prompting to install # developer tools. Any system running Mac OS X 10.7 or # later (Darwin 11 and later) is required to have a 64-bit # processor. This is not true of the ARM version of Darwin # that Apple uses in portable devices. UNAME_PROCESSOR=x86_64 fi echo "$UNAME_PROCESSOR"-apple-darwin"$UNAME_RELEASE" exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = x86; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo "$UNAME_PROCESSOR"-"$UNAME_MACHINE"-nto-qnx"$UNAME_RELEASE" exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; NEO-*:NONSTOP_KERNEL:*:*) echo neo-tandem-nsk"$UNAME_RELEASE" exit ;; NSE-*:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk"$UNAME_RELEASE" exit ;; NSR-*:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk"$UNAME_RELEASE" exit ;; NSV-*:NONSTOP_KERNEL:*:*) echo nsv-tandem-nsk"$UNAME_RELEASE" exit ;; NSX-*:NONSTOP_KERNEL:*:*) echo nsx-tandem-nsk"$UNAME_RELEASE" exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) echo "$UNAME_MACHINE"-"$UNAME_SYSTEM"-"$UNAME_RELEASE" exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = 386; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo "$UNAME_MACHINE"-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux"$UNAME_RELEASE" exit ;; *:DragonFly:*:*) echo "$UNAME_MACHINE"-unknown-dragonfly"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`" exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "$UNAME_MACHINE" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit ;; i*86:skyos:*:*) echo "$UNAME_MACHINE"-pc-skyos"`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'`" exit ;; i*86:rdos:*:*) echo "$UNAME_MACHINE"-pc-rdos exit ;; i*86:AROS:*:*) echo "$UNAME_MACHINE"-pc-aros exit ;; x86_64:VMkernel:*:*) echo "$UNAME_MACHINE"-unknown-esx exit ;; amd64:Isilon\ OneFS:*:*) echo x86_64-unknown-onefs exit ;; esac echo "$0: unable to guess system type" >&2 case "$UNAME_MACHINE:$UNAME_SYSTEM" in mips:Linux | mips64:Linux) # If we got here on MIPS GNU/Linux, output extra information. cat >&2 <&2 </dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = "$UNAME_MACHINE" UNAME_RELEASE = "$UNAME_RELEASE" UNAME_SYSTEM = "$UNAME_SYSTEM" UNAME_VERSION = "$UNAME_VERSION" EOF exit 1 # Local variables: # eval: (add-hook 'write-file-functions 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: