[
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Describe the bug**\nA clear and concise description of what the bug is, what happened and what you expected to happen.\n\n**Environment**\n - neon version: [e.g. 0.31.1]\n - OS: [e.g. Ubuntu]\n - SSL library version: [e.g. OpenSSL 1.1.1]\n\n**To Reproduce**\nPlease provide a minimal code snippet using the neon API to trigger the issue.\n\n**Debugging output**\nPlease include neon debugging output generated by e.g. `ne_debug_init(stderr, NE_DBG_HTTP);`\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE/pull_request_template.md",
    "content": "Fixes XXXX (fixes #NNN)\n\n```\nChangelog:\n\n```\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: Build and test\n\non:\n  push:\n    branches:\n    - master\n    - '*.x'\n    paths-ignore:\n    - 'doc/**'\n    - NEWS\n  pull_request:\n    branches:\n    - master\n    - '*.x'\n    paths-ignore:\n    - 'doc/**'\n    - NEWS\n\njobs:\n  build:\n    runs-on: ${{ matrix.os }}\n    strategy:\n      fail-fast: true\n      matrix:\n        os: [ubuntu-22.04, ubuntu-24.04, ubuntu-22.04-arm]\n        conf-shared: [--enable-static, --enable-shared --enable-warnings=error ]\n        conf-xml: [--with-expat, --with-libxml2 ]\n        conf-ssl: [--without-ssl, --with-ssl=openssl, --with-ssl=gnutls --with-libntlm]\n        conf-memleak: [--disable-memleak, --enable-memleak]\n        conf-debug: [--enable-debug, --disable-debug]\n        conf-gssapi: [--with-gssapi, --without-gssapi]\n        exclude:\n            - os: [ubuntu-22.04, ubuntu-24.04]\n              conf-shared: --enable-static\n            - conf-gssapi: --without-gssapi\n              conf-ssl: [--without-ssl, --with-ssl=gnutls --with-libntlm]\n            - conf-xml: --with-libxml2\n              conf-gssapi: --without-gssapi\n            - os: ubuntu-22.04-arm\n              conf-xml: --with-libxml2\n            - os: ubuntu-22.04-arm\n              conf-ssl: [--without-ssl, --with-ssl=gnutls --with-libntlm]\n            - os: ubuntu-22.04-arm\n              conf-debug: --disable-debug\n            - os: ubuntu-22.04-arm\n              conf-gssapi: --without-gssapi\n            - os: ubuntu-22.04-arm\n              conf-memleak: --enable-memleak\n            - os: ubuntu-22.04-arm\n              conf-shared: --enable-static\n    steps:\n    - uses: actions/checkout@v2\n    - run: ./autogen.sh\n    - run: case \"${{matrix.conf-ssl}}\" in\n           *gnutls*) sudo apt-get update && sudo apt-get -y install libgnutls28-dev gnutls-bin libntlm0-dev ;;\n           esac\n    - run: case ${{matrix.conf-gssapi}} in\n           *with-gssapi) sudo apt-get update && sudo apt-get -y install libkrb5-dev ;;\n           esac\n    - run: ./configure ${{matrix.conf-shared}} ${{matrix.conf-xml}}\n                       ${{matrix.conf-ssl}} ${{matrix.conf-memleak}}\n                       ${{matrix.conf-debug}} ${{matrix.conf-gssapi}}\n    - run: make -j`nproc`\n    - run: make -j`nproc` check TEST_QUIET=0 TEST_COLOUR=1\n    - if: failure()\n      run: if test -f test/debug.log; then cat test/debug.log; fi\n    - run: test/checksyms.sh src/.libs/libneon.so\n      if: ${{ matrix.conf-debug == '--enable-debug' && matrix.conf-shared != '--enable-static' && matrix.conf-memleak == '--disable-memleak' }}\n\n  containers:\n    runs-on: ubuntu-latest\n    strategy:\n      fail-fast: true\n      matrix:\n        image: [\"quay.io/centos/centos:stream9\",\n                \"fedora:latest\"]\n    container:\n      image: ${{ matrix.image }}\n    steps:\n      - run: dnf update -y && dnf install -y autoconf make expat-devel\n                  openssl openssl-devel krb5-devel libtool zlib-devel gawk\n      - if: contains(matrix.image, 'fedora')\n        run: dnf install -y libntlm-devel\n      - uses: actions/checkout@v3\n      - run: ./autogen.sh\n      - run: ./configure --with-ssl=openssl --with-expat --enable-debug --with-gssapi\n                         ${{ contains(matrix.image, 'fedora') && '--with-libntlm' || '' }}\n                         --enable-warnings=error --without-pakchois\n      - run: make -j`nproc`\n      - run: make -j`nproc` check TEST_QUIET=0 TEST_COLOUR=1\n"
  },
  {
    "path": ".github/workflows/sanity.yml",
    "content": "name: Build sanity and docs checks\n\non:\n  push:\n    branches:\n    - master\n    - '*.x'\n  pull_request:\n    branches:\n    - master\n    - '*.x'\n\njobs:\n  sanity-checks:\n    name: Build sanity and docs checks\n    runs-on: ubuntu-latest\n    container:\n      image: fedora:latest\n    steps:\n      - run: dnf update -y && dnf install -y autoconf make expat-devel openssl-devel libtool zlib-devel gcc-c++ xmlto gawk\n      - uses: actions/checkout@v3\n      - run: ./autogen.sh\n      - run: ./configure --with-ssl=openssl --with-expat --enable-debug\n      - run: make -C src check-incl\n      - run: make -C src check-c++\n      - run: make docs\n"
  },
  {
    "path": ".gitignore",
    "content": "/config.h.in\n/config.h\n/configure\n/config.status\n/config.log\n/conftest.c\n/Makefile\n/aclocal.m4\n/*.cache\n/libtool\n/neon-config\n/reconf*\n/confdefs.h\n/ltmain.sh\n/ltconfig\n/config.sub\n/config.guess\n/*.out\n/*.log\n/.version\n/config.hw\n/neon.pc\n/clog\n/ChangeLog\n/install-sh\n/po/*.gmo\n/doc/*.?\n/doc/*.html\n/doc/*.pdf\n/doc/*.ps\n/doc/*.tex\n/doc/*.sgml\n/doc/*.junk\n/doc/html\n/doc/man\n/doc/man3\n/doc/man1\n/doc/version.xml\n/doc/date.xml\n**/.libs\n/macros/libtool.m4\n/macros/ltoptions.m4\n/macros/ltsugar.m4\n/macros/lt~obsolete.m4\n/macros/ltversion.m4\n"
  },
  {
    "path": ".gitleaks.toml",
    "content": "[allowlist]\ndescription = \"Global Allowlist\"\n\n# Ignore based on any subset of the file path\npaths = [\n    # Ignore the pregenerated server keys\n    '''test\\/.*\\.key$''',\n  ]\n"
  },
  {
    "path": ".package",
    "content": "announce-list=neon@lists.manyfish.co.uk\n"
  },
  {
    "path": ".release.sh",
    "content": "#!/bin/sh\n\nset -ex\n\nmajor=`echo $1 | awk -F. '{print $1;}'`\nminor=`echo $1 | awk -F. '{print $2;}'`\nrelease=`echo $1 | awk -F. '{print $3;}'`\nversion=$1\n\nfor f in config.hw; do\nin=$f.in\nout=$f\nsed -e \"s/@VERSION@/$version/g\" \\\n    -e \"s/@MAJOR@/$major/g\" \\\n    -e \"s/@MINOR@/$minor/g\" \\\n    -e \"s/@RELEASE@/$release/g\" \\\n    -e \"s,@top_srcdir@,`pwd`,g\" < $in > $out\ndone\n\necho $1 > .version\n\n# for the documentation:\ndate +\"%e %B %Y\" | tr -d '\\n' > doc/date.xml\necho -n $1 > doc/version.xml\n\nALL_LINGUAS=`echo po/*.po | sed 's,po/,,g;s,\\.po,,g'`\n\n# Try to create a valid Makefile\ntmp=`mktemp /tmp/neon-XXXXXX`\nsed -e 's,@SET_MAKE@,,;s,@SHELL@,/bin/sh,' \\\n    -e \"s,@top_srcdir@,`pwd`,\" \\\n    -e \"s,@srcdir@,`pwd`,\" \\\n    -e \"s,@ALL_LINGUAS@,${ALL_LINGUAS},\" \\\n    < Makefile.in > $tmp\nmake -f $tmp docs compile-gmo\nrm -f $tmp\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: c\nos: linux\ndist: xenial\naddons:\n  apt:\n    packages:\n      - xmlto\n      - libxml2-dev\n      - libnss3-tools\n      - libproxy-dev\nenv:\n  global:\n    - MARGS=\"-j2 check\"\nmatrix:\n  include:\n    - name: Disable-all\n      env: CONF=\"--without-libproxy --without-gssapi --without-zlib --disable-nls --disable-debug --disable-webdav\"\n    - name: Static UBSan w/OpenSSL\n      env: CONF=\"--enable-static --with-ssl=openssl\" CFLAGS=\"-fsanitize=undefined -fno-sanitize-recover=undefined\" LIBS=-lubsan NEON_LIBS=-lubsan\n    - name: Static 32-bit w/OpenSSL\n      env: CONF=\"--enable-static --with-ssl=openssl\" CC='gcc -m32'\n      addons:\n        apt:\n          packages:\n            - libc6-dev-i386\n            - gcc-multilib\n            - libexpat1-dev:i386\n            - libssl-dev:i386\n            - lib32z1-dev\n    - name: OpenSSL on arm64\n      arch: arm64\n      env: CONF=\"--with-ssl=openssl\"\n    - name: OpenSSL on s390x\n      arch: s390x\n      env: CONF=\"--with-ssl=openssl\"\n    - name: Copyright check\n      env: CONF=\"--without-libproxy --without-gssapi --without-zlib --disable-nls --disable-debug --disable-webdav\" MARGS=\"update-copyright\"\n  allow_failures:\n    # s390x builds currently flaky\n    - name: OpenSSL on s390x\n      arch: s390x\n      env: CONF=\"--with-ssl=openssl\"\n\nscript: ./autogen.sh && ./configure --enable-warnings $CONF && make $MARGS\n"
  },
  {
    "path": "AUTHORS",
    "content": "neon is Copyright (C) 1999-2007 Joe Orton <joe@manyfish.co.uk>\nPortions are:\nCopyright (C) 1999-2000 Tommi Komulainen <Tommi.Komulainen@iki.fi>\nCopyright (C) 1999-2000 Peter Boos <pedib@colorfullife.com>\nCopyright (C) 1991, 1995, 1996, 1997 Free Software Foundation, Inc.\nCopyright (C) 2004 Aleix Conchillo Flaque <aleix@member.fsf.org>\nCopyright (C) 2004 Jiang Lei <tristone@deluxe.ocn.ne.jp>\nCopyright (C) 2004-2005 Vladimir Berezniker @ http://public.xdi.org/=vmpn\n"
  },
  {
    "path": "INSTALL.win32",
    "content": "Building neon on Windows uses a single Nmake neon.mak file.  By\nplacing various parameters on nmake's command line, you can specify\nexactly the features and behavior of the Neon libraries.  The\nparameters are additive, so to add more features, add the command line\noptions specified in the particular section below.\n\nAll the builds described below should work with Microsoft VC++ 5 and\n6.\n\nBuild neon\n__________\n\nThis is the most basic version of the Neon library you can build.  It\ndoes not require any third party libraries, but you do not get the\nfull capabilities of Neon.\n\nCompile Neon with no parameters\n\n  nmake /f neon.mak\n\nAfter compiling the library, the directory contains libneon.lib,\nagainst which you can link your program.\n\n\nBuild neon with WebDAV support\n______________________________\n\nTo compile Neon with WebDAV support, Neon must compile and link\nagainst a third-party XML parser, either expat, expat-lite, libxml or\nlibxml2.  This Windows neon.mak file is designed to compile and link\nagainst the pre-built Expat Windows libraries version 1.95.X or newer.\nThis library is available for download from\n\n  http://sourceforge.net/projects/expat/\n\nDownload the latest expat_win32bin package named\n\n  expat_win32bin_X_YY_Z.exe\n\nand install it on your system.  It wants to install itself into\nQ:\\some\\dir\\Expat-X.Y.ZZ.  Choose your installation location for expat\nand then compile Neon with\n\n  nmake /f neon.mak EXPAT_SRC=\\path\\to\\Expat-X.YY.Z\n\nNOTE: When you run your program make sure the LIBEXPAT.DLL from expat\nis accessible, i.e. is in your PATH.\n\nThis should work with Microsoft VC++ 5 and 6.\n\n\nBuild neon with dynamically linked SSL support\n______________________________________________\n\nTo build neon on Windows with SSL support you need OpenSSL already\ninstalled on your system (I used OpenSSL 0.9.7g).  It can be\ndownloaded from\n\n  http://www.openssl.org/source/openssl-0.9.7g.tar.gz\n\nAfter compiling OpenSSL, now simply point make to the OpenSSL sources:\n\n  nmake /f neon.mak OPENSSL_SRC=\\path\\to\\openssl\n\nNOTE: The include files for OpenSSL reside in inc32/ directory\n(\"../openssl-0.9.7g/inc32\").\n\nNOTE: Make sure that your program is linked against libeay32.lib and\nssleay32.lib (normally in \"../openssl-0.9.7g/out32dll\") and that\nlibeay32.dll and ssleay32.dll is accessible, i.e. is in your PATH.\n\n\nBuild neon with statically linked OpenSSL support\n_________________________________________________\n\nIf you want to statically link against OpenSSL, then add the\nOPENSSL_STATIC parameter.\n\n  nmake /f neon.mak OPENSSL_SRC=\\path\\to\\openssl OPENSSL_STATIC=yes\n\n\nBuild neon with statically linked Zlib support\n______________________________________________\n\nIf you want to build Neon with the capability to decompress compressed\ncontent, then you need to compile against the Zlib library.\n\nNeon's neon.mak file will compile and link the Zlib sources. You need\nZlib 1.2.1 or later, as previous versions do not include build scripts\nfor Win32.\n\nHere's how to compile in Zlib support.\n\n  1) Get one of the Zlib source file packages in Zip format from\n     http://www.gzip.org/zlib/; for example,\n     http://www.gzip.org/zlib/zlib121.zip\n  2) Unzip it.\n\nNow add the ZLIB_SRC parameter to Neon's neon.mak pointing to your\nnewly compiled zlib.\n\n  nmake /f neon.mak ZLIB_SRC=\\path\\to\\zlib\n\n\nBuild neon with dynamically linked Zlib support\n_______________________________________________\n\nTo build Neon with dynamically linked Zlib support, use the\ninstructions for the statically linked Zlib support above and add the\nZLIB_DLL parameter\n\n  nmake /f neon.mak ZLIB_SRC=\\path\\to\\zlib ZLIB_DLL=yes\n\n\nBuild neon with IPv6 support\n____________________________\n\nTo build neon with support for IPv6, use parameter ENABLE_IPV6.\n\n  nmake /f neon.mak ENABLE_IPV6=yes\n\nThis requires a copy of the Platform SDK which contains the IPv6\nheaders and libraries.\n\nBuild neon with debugging support\n_________________________________\n\nSet the DEBUG_BUILD parameter\n\n  nmake /f neon.mak DEBUG_BUILD=yes\n\nIt does not matter what value DEBUG_BUILD is set to, as long as it is\nnot set to \"\".\n\nAfter compiling the library, the directory contains libneonD.lib,\nagainst which you can link your program.\n"
  },
  {
    "path": "Makefile.in",
    "content": "# Copyright (C) 2001-2009 Joe Orton <joe@manyfish.co.uk>\n# Copyright (C) 1994, 1995-8, 1999, 2000 Free Software Foundation, Inc.\n# This Makefile.in is free software; the Free Software Foundation\n# gives unlimited permission to copy and/or distribute it,\n# with or without modifications, as long as this notice is preserved.\n\n# This program is distributed in the hope that it will be useful,\n# but WITHOUT ANY WARRANTY, to the extent permitted by law; without\n# even the implied warranty of MERCHANTABILITY or FITNESS FOR A\n# PARTICULAR PURPOSE.\n\n# libtool bits mostly stolen from libxml and libtool/demo\n\nSHELL = @SHELL@\n\nprefix = @prefix@\nexec_prefix = @exec_prefix@\nbindir = @bindir@\nlibdir = @libdir@\nmandir = @mandir@\nman1dir = $(mandir)/man1\nman3dir = $(mandir)/man3\ndatarootdir = @datarootdir@\ndatadir = @datadir@\ndocdir = $(datadir)/doc/neon-@NEON_VERSION@\nincludedir = @includedir@\nneonincludes = $(includedir)/neon\npkgconfigdir = $(libdir)/pkgconfig\nlocaledir = $(datadir)/locale\n\ntop_srcdir = @top_srcdir@\ntop_builddir = .\nsrcdir = @srcdir@\nVPATH = @srcdir@\n\n@SET_MAKE@\n\nLDFLAGS = -L. @LDFLAGS@\nLIBS = @LIBS@\nCC = @CC@\nINSTALL_PROGRAM = @INSTALL_PROGRAM@\nINSTALL_DATA = @INSTALL_DATA@\nINSTALL_SCRIPT = @INSTALL_SCRIPT@\nINSTALL = @INSTALL@\ntransform = @program_transform_name@\n\nLIBTOOL = @LIBTOOL@\nXMLTO = xmlto\nGCOV = gcov\nXGETTEXT_OPTS = --keyword=_ --keyword=N_ --msgid-bugs-address=https://github.com/notroj/neon \\\n\t\t--default-domain=neon --flag ne_print_request_header:3:c-format \\\n\t\t--flag ne_snprintf:3:c-format --flag ne_vsnprintf:3:c-format \\\n\t\t--flag ne_set_error:2:c-format\nPOTFILE = $(top_srcdir)/po/neon.pot\nXGETTEXT = xgettext\nMSGFMT = msgfmt\nMSGMERGE = msgmerge\n\nLINGUAS = @ALL_LINGUAS@\n\n# The headers to distribute - making up the public interface of neon\nDIST_HEADERS = ne_request.h ne_session.h ne_utils.h ne_uri.h ne_socket.h  \\\n\tne_basic.h ne_207.h ne_props.h ne_xml.h ne_dates.h ne_string.h\t  \\\n\tne_defs.h ne_locks.h ne_alloc.h ne_md5.h ne_i18n.h ne_redirect.h  \\\n\tne_auth.h ne_compress.h ne_acl.h ne_ssl.h ne_xmlreq.h ne_pkcs11.h \\\n\tne_acl3744.h\n\nall: subdirs\n\ncheck: subdirs\n\t@cd test && $(MAKE) check\n\n# Useful for doing coverage analysis; use e.g.:\n#   make TESTS=string-tests MODULE=ne_string.c cover\ncover: subdirs\n\t@rm -f src/*.*da test/common/*.*da test/*.*da\n\t@cd test && $(MAKE) check\n\t@cd src && $(GCOV) -cb $(MODULE)\n\n# as per 'cover' target; prints list of functions without 100% coverage\nuncover: subdirs\n\t@rm -f src/*.*da test/common/*.*da test/*.*da\n\t@cd test && $(MAKE) check\n\t@cd src && $(GCOV) -cb $(MODULE)\n\t@grep ^function src/$(MODULE).gcov | grep -v 'executed 100' | sort -nr -k 9,9\n\nsubdirs:\n\t@cd src && $(MAKE)\n\n# Regenerating the docs requires xmlto to be installed, this target is\n# executed when release tarballs are generated.\ndocs: docs-man docs-html\n\ndocs-man:\n\trm -rf doc/man; mkdir -p doc/man\n\t$(XMLTO) -o `pwd`/doc/man -x $(srcdir)/doc/man.xsl man $(srcdir)/doc/manual.xml\n\ndocs-pdf:\n\t$(XMLTO) -o `pwd`/doc pdf $(srcdir)/doc/manual.xml\n\ndocs-ps:\n\t$(XMLTO) -o `pwd`/doc ps $(srcdir)/doc/manual.xml\n\ndocs-html:\n\ttest -d doc/html && rm -rf doc/html || true\n\tmkdir -p doc/html\n\tcp $(srcdir)/doc/manual.css doc/html\n\t$(XMLTO) -o `pwd`/doc/html -x $(srcdir)/doc/html.xsl html $(srcdir)/doc/manual.xml\n\n# Validate the manual source\ndocs-valid:\n\txmllint --noout --valid $(srcdir)/doc/manual.xml\n\nclean:\n\t@cd src && $(MAKE) clean\n\t@cd test && $(MAKE) clean\n\ndistclean: clean\n\trm -rf Makefile config.h neon.pc config.status src/Makefile libtool config.log config.cache neon-config autom4te*.cache test/Makefile\n\nagain: clean\n\nMakefile: $(srcdir)/Makefile.in\n\t@./config.status Makefile\n\nneon-config: $(srcdir)/neon-config.in\n\t@./config.status neon-config\n\ninstall-docs: install-man install-html\n\ninstall-html:\n\t$(INSTALL) -d $(DESTDIR)$(docdir)/html\n\tfor d in doc/html/*.html; do \\\n\t\t$(INSTALL_DATA) $$d $(DESTDIR)$(docdir)/html; \\\n\tdone\n\ninstall-man:\n\t$(INSTALL) -d $(DESTDIR)$(man3dir)\n\t$(INSTALL) -d $(DESTDIR)$(man1dir)\n\tfor m in doc/man/*.3; do \\\n\t $(INSTALL_DATA) $$m $(DESTDIR)$(man3dir); done\n\tfor m in doc/man/*.1; do \\\n\t $(INSTALL_DATA) $$m $(DESTDIR)$(man1dir); done\n\ninstall: install-@ALLOW_INSTALL@\n\ninstall-memleak:\n\t@echo \"ERROR: The neon internal memory leak checking code is for testing\"\n\t@echo \"ERROR: purposes only; this copy of neon must not be installed.\"\n\t@false\n\ninstall-yes: install-lib install-headers install-config install-docs install-nls\n\n# libtool does all the necessary magic here\ninstall-lib: subdirs\n\t$(INSTALL) -d $(DESTDIR)$(libdir)\n\t$(LIBTOOL) --mode=install $(INSTALL) src/libneon.la \\\n\t\t$(DESTDIR)$(libdir)/libneon.la\n\ninstall-headers:\n\t$(INSTALL) -d $(DESTDIR)$(neonincludes)\n\t@for h in $(DIST_HEADERS); do \\\n\t\techo Installing $$h into $(DESTDIR)$(neonincludes); \\\n\t\t$(INSTALL_DATA) $(srcdir)/src/$$h $(DESTDIR)$(neonincludes)/$$h \\\n\t\t\t|| exit 1; \\\n\tdone\n\ninstall-config: neon-config neon.pc\n\t$(INSTALL) -d $(DESTDIR)$(bindir)\n\t@echo Installing neon-config into $(DESTDIR)$(bindir)\n\t@$(INSTALL_SCRIPT) neon-config \\\n\t\t$(DESTDIR)$(bindir)/`echo neon-config|sed '$(transform)'`\n\t$(INSTALL) -d $(DESTDIR)$(pkgconfigdir)\n\t$(INSTALL_DATA) neon.pc $(DESTDIR)$(pkgconfigdir)/neon.pc\n\ninstall-tests: install-lib\n\t@cd test && make install\n\ninstall-nls: install-nls-@NE_FLAG_I18N@\n\ninstall-nls-no:\n\t@echo NLS not enabled.\n\ninstall-nls-yes:\n\t@for f in $(LINGUAS); do \\\n\t $(INSTALL) -d $(DESTDIR)$(localedir)/$$f/LC_MESSAGES; \\\n\t $(INSTALL_DATA) $(srcdir)/po/$$f.gmo $(DESTDIR)$(localedir)/$$f/LC_MESSAGES/neon.mo; \\\n\tdone\n\nChangeLog:\n\tsvn log > $@\n\nupdate-po:\n\t@xgettext $(XGETTEXT_OPTS) $(top_srcdir)/src/ne*.c -o $(POTFILE)\n\t@for f in $(LINGUAS); do \\\n\t echo \"> Updating \\\"$$f\\\" catalog:\"; \\\n\t $(MSGMERGE) --update $(top_srcdir)/po/$$f.po $(POTFILE); \\\n\t $(MSGFMT) --output /dev/null --check-format $(top_srcdir)/po/$$f.po || exit 1; \\\n\tdone\n\ncompile-gmo:\n\t@for f in $(LINGUAS); do \\\n\t echo \"> Compiling \\\"$$f\\\" catalog:\"; \\\n\t $(MSGFMT) --statistics -c -o po/$$f.gmo $(top_srcdir)/po/$$f.po; \\\n\tdone\n\nupdate-copyright: Makefile\n\t@mv README.md README.orig\n\t@(sed -n '/^Copyright/q;p' < README.orig; \\\n\t grep -h Copyright src/*.[ch] po/*.po macros/*.m4 | \\\n\t sed -r 's/\\(C\\) [12].+[0-9],? /(C) /;s/^\\#*//;s/^dnl//;s/<.*>//g;s/ @ .*//;s/[ ]*//;s/ *$$//;/Orton/d' | \\\n\t sort -u; echo '~~~') > README.md\n\t@diff -u README.orig README.md\n\t@rm -f README.orig\n\ndoc-status:\n\t@echo \"Missing docs for:\"\n\t@pass=0; fail=0; for f in `nm -D src/.libs/libneon.so | sed -n '/ T /{s/.* T //;s/@@.*//g;p;}' | sort`; do\t\\\n\t   if test -f doc/man/$$f.3; then\t\t\t\t\t\t\t\t\t\t\\\n\t\techo \"PASS: $$f\"; pass=$$((pass + 1)); else\t\t\t\t\t\t\t\t\\\n\t\techo \"FAIL: $$f\"; fail=$$((fail + 1)); fi;\t\t\t\t\t\t\t\t\\\n\tdone; echo \"Overall: Coverage=$$((100*pass / fail))%\"; test $$fail -eq 0\n"
  },
  {
    "path": "NEWS",
    "content": "Changes in release 0.37.1:\n* Bug fixes:\n - fix compile warnings with OpenSSL 4.0.0-alpha1\n - fix NTLM test case failures on big-endian systems\n - fix test suite with SSL enabled in VPATH builds\n\nChanges in release 0.37.0:\n* Interface changes:\n - API and ABI backwards-compatible with 0.27.x and later\n* New interfaces and feaures:\n - ne_socket.h: add ne_sock_handshake(); deprecate ne_ssl_connect_ssl();\n   add ne_sock_getcert(), ne_iaddr_put()\n - ne_ssl.h: add ne_ssl_clicert_copy(), ne_ssl_context_trustdefca(),\n   ne_ssl_check_certificate(), ne_ssl_context_set_clicert(),\n   ne_ssl_context_set_ccprovide()\n - ne_request.h: add ne_get_response_trailer(), ne_response_trailer_iterate()\n   headers from the chunked trailer section are no longer merged with\n   response headers to conform with RFC 9110 section 6.5\n - ne_string.h: add ne_strlower(), ne_strupper(), ne_mknonce(), NE_HASH_SHA1\n - dropped bundled NTLM code; Libntlm <https://gitlab.com/gsasl/libntlm>\n   is now required for NTLM authentication support\n - ne_utils.h: ne_version_match() description fixed to match code;\n   add ne_version_library()\n* Bug fixes:\n - fix ne_xml_set_encoding() failure case with libxml 2.13+.\n - ne_session_create() passed-in scheme now always lower-cased\n\nChanges in release 0.36.0:\n* Interface changes:\n - API and ABI backwards-compatible with 0.27.x and later\n* New interfaces and features:\n - ne_xml.h: add ne_xml_set_encoding()\n - ne_xmlreq.h: add ne_xml_dispatchif_request(); this and\n   ne_xml_dispatch_request() both invoke ne_xml_set_encoding()\n   with the charset= from the Content-Type, if present\n - ne_request.h: add ne_read_response_to_buffer()\n - ne_basic.h: add ne_getbuf()\n* Bug fixes:\n - fix ne_simple_request() failures on non-207 XML responses (#208)\n - invoke the notifier callback again at the end of a chunked response\n - fix a failure case where a proxy connection could get reused after\n   SSL proxy tunnel setup failed at the proxy\n - fix ne_sock_* OpenSSL 3.4 error handling on Windows (#213)\n - ne_get_content_type() updated for RFC 7303: default charset\n   for text/ media types is removed\n* Various documentation updates.\n\nChanges in release 0.35.0:\n* Interface changes:\n - API and ABI backwards-compatible with 0.27.x and later\n - pakchois-based PKCS#11 support is now deprecated\n* Interface clarifications:\n - ne_md5_read_ctx() may return NULL\n* New interfaces and features:\n - ne_request.h: add ne_get_response_retry_after()\n - ne_uri.h: add NE_PATH_NONPC escaping rule\n - ne_string.h: add ne_strhextoul()\n - ne_ssl.h: add ne_ssl_clicert_fromuri(), a simpler API\n   to retrieve client certs based on (e.g.) PKCS#11 URIs;\n   only supported with OpenSSL currently.\n - ne_session.h: add ne_status_handshake to notifier API\n* Bug fixes:\n - ne_path_escape() now follows NE_PATH_NONPC pct-encoding\n   rule by default (fixes #181)\n - ne_md5_*(): for OpenSSL, now uses the EVP* API\n - session caching fixes for OpenSSL\n* \"BUGS\" document removed, use https://github.com/notroj/neon/issues\n\nChanges in release 0.34.2:\n* Fix regression in NTLM auth in 0.34.0 (issue #190).\n* Add docs for ne_ssl_proto_name, ne_ssl_protovers, ne_get_request_target.\n\nChanges in release 0.34.1:\n* Fix regression in 207 parsing of <status> elements which omit\n  a reason-phrase (issue #188).\n* Fix ne_move() to submit lock tokens for the parent collection\n  of a source resource locked with depth: 0.\n\nChanges in release 0.34.0:\n* Interface changes:\n - API and ABI backwards-compatible with 0.27.x and later\n - NE_SESSFLAG_SSLv2 is now ignored\n* New interfaces and features:\n - ne_request.h: add ne_get_response_location(),\n   add ne_get_request_target()\n - ne_redirect.h: adds relative URI resolution per RFC 9110\n - ne_socket.h: add ne_iaddr_set_scope(), ne_iaddr_get_scope(),\n   ne_sock_getproto()\n - ne_session.h: add NE_SESSFLAG_STRICT session flag\n - ne_session.h: ne_session_create() now accepts scoped IPv6\n   link-local literal addresses following the RFC 6874 syntax;\n - ne_session.h: add ne_ssl_set_protovers() to configure TLS\n   protocol version ranges\n - ne_utils.h: add NE_FEATURE_GSSAPI, NE_FEATURE_LIBPXY feature flags\n - ne_ssl.h: add ne_ssl_proto_name()\n - HTTP strictness/compliance updated for RFC 9110/9112;\n   notably stricter in parsing header field line, chunked\n   transfer-coding, status-line.\n* Bug fixes:\n - auth: the 'realm' string passed to credentials callback is now\n   cleaned of non-printable characters.\n* Documentation & header updates for RFC 9110/9112.\n* New NE_MINIMUM_VERSION() autoconf macro for better version handling.\n\nChanges in release 0.33.0:\n* Interface changes:\n - API and ABI backwards-compatible with 0.27.x and later\n* Interface clarifications:\n - ne_locks.h: note that returned lock may have a different URI\n   than the path passed to ne_lock_discover() due to added\n   support for RFC 4918 \"lockroot\" in lock discovery\n - ne_request.h: ne_request_create() takes a \"target\" rather\n   than a path and this can also be an absolute-URI\n - ne_request.h: never-used ne_free_hooks typedef removed\n - ne_dates.h: clarified error cases (behaviour unchanged)\n - ne_session.h: ne_session_create() 'host' must match RFC 3986\n   syntax; IPv6 literal addresses must use [] brackets\n* New interfaces and features:\n - added new configure flag --enable-auto-libproxy which enables\n   libproxy by default for new sessions (Jan-Michael Brummer)\n - ne_locks.h: added DAV:lockroot support per RFC 4918\n - ne_ssl.h: ne_ssl_trust_default_ca() now a no-op for non-SSL sessions\n - ne_request.h: add ne_add_interim_handler() to handle interim\n   (1xx) responses; headers in interim responses are now accessible\n - ne_basic.h: add ne_putbuf()\n - ne_strhash: SHA-512/256 now supported for LibreSSL 3.8+ (orbea)\n - response handling no longer applies a maximum limit on 1xx interim\n   responses; an overall timeout equal to the read timeout is now\n   applied if a read timeout is configured and 1XXTIMEOUT is enabled\n - ne_request.h: add NE_REQFLAG_1XXTIMEOUT\n* Bug fixes:\n - test suite now works correctly on IPv6-only hosts (Jeremy Sowden)\n - fixes for building against LibreSSL (orbea)\n - ne_uri_parse() fixes for handling URI with no path and catch\n   some invalid URIs which were allowed (fasticc)\n - retry requests after a 408 response on a persisted connection\n - 207 error strings are cleaned and compressed to a single line\n - fixed thread-safety in ne_rfc1123_date where gmtime_r is available\n - ne_lock_refresh() fixed to use a non-idempotent request\n - TLS name verification updated to match RFC 9110/6125, added strict\n   handling of IP literals vs DNS names\n\nChanges in release 0.32.5:\n* NOTE: Since 0.32.0 the \"$KRB5_CONFIG\" environment variable is ignored\n  when running configure. Use KRB5_CONF_TOOL instead to specify an\n  alternative to /usr/bin/krb5-config.\n* Fail for configure --with-gssapi if GSSAPI can't be enabled (issue #102)\n* Add Georgian translation (NorwayFun)\n* Fixes for Windows MSYS2/MinGW build, including cross-build (Jim Klimov)\n\nChanges in release 0.32.4:\n* Fix Digest regression in allowing implicit algorithm= (issue #88)\n* Fix Digest to safely allow spaces in usernames (without userhash)\n* ne_ssl_trust_default_ca() now uses the system's trusted CAs\n  with GnuTLS where supported (matching behaviour of OpenSSL)\n\nChanges in release 0.32.3:\n* Improvements and fixes to Windows build (Chun-wei Fan)\n* Fix finding pkg-config when cross-compiling (Hugh McMaster)\n* Fix Digest cnonce entropy sources in non-SSL builds\n* Fix cases where Digest usernames were rejected as non-ASCII\n* Fix build failures with OpenSSL 1.1 on some platforms\n\nChanges in release 0.32.2:\n* Fix auth handling for request-target of \"*\" (regressed since 0.31.x)\n* Fix bindtextdomain() detection on OS X (Daniel Macks)\n* Fix regeneration of docs in \"make install\" (Lonnie Abelbeck)\n* Fixes for NetBSD build (Thomas Klausner)\n\nChanges in release 0.32.1:\n* Fix configure CFLAGS handling in Kerberos detection.\n* Various spelling fixes.\n\nChanges in release 0.32.0:\n* Interface changes:\n - API and ABI backwards-compatible with 0.27.x and later\n - NE_AUTH_DIGEST now only enables RFC 2617/7616 auth by default;\n   to enable weaker RFC 2069 Digest, use NE_AUTH_LEGACY_DIGEST\n   (treated as a security enhancement, not an API/ABI break)\n* Interface clarifications:\n - ne_auth.h: use of non-ASCII usernames with the ne_auth_creds\n   callback type is now rejected for Digest auth since the\n   encoding is not specified.  ne_add_auth() can be used instead.\n - ne_request.h: the ne_create_request_fn callback is passed the\n   request-target using RFC 7230 terminology\n* New interfaces and features:\n - ne_string.h: added ne_strhash(), ne_vstrhash(), ne_strparam()\n - ne_auth.h: added RFC 7616 (Digest authentication) support,\n   including userhash=, username*= and SHA-2 algorithms\n   (SHA-2 requires GnuTLS/OpenSSL).  added NE_AUTH_LEGACY_DIGEST\n - ne_auth.h: added ne_add_auth() unified auth callback interface,\n   accepts (only) UTF-8 usernames, uses a larger password buffer,\n   and has different/improved attempt counter semantics.\n - RFC 7617 scoping rules are now applied for Basic authentication.\n - ne_ssl.h: added ne_ssl_cert_hdigest()\n - ne_socket.h: added ne_sock_shutdown()\n - sendmsg()/send() are used with the MSG_NOSIGNAL flag to write to\n   sockets on Unix, rather than write()/writev(), avoiding SIGPIPE\n - explicit_bzero() is used where available to clear credentials\n* Bug fixes:\n - fixed TLS connection shutdown handling for OpenSSL 3\n - fix various Coverity and cppcheck warnings (Sebastian Reschke)\n - Kerberos library detection uses pkg-config where possible.\n - fix some configure checks on Win32 (Christopher Degawa)\n - fix some configure errors on MacOS (Ryan Schmidt)\n\nChanges in release 0.31.2:\n* Fix ne_md5_read_ctx() with OpenSSL on big-endian architectures.\n* Fix GCC 10 warning in PKCS#11 build.\n* Fix OpenSSL build w/o deprecated APIs (Rosen Penev).\n* Fix unnecessary MD5 test for non-Digest auth (Sebastian Reschke).\n* Fix hang on SSL connection close with IIS (issue #11).\n* Fix ar, ranlib detection when cross-compiling (Sergei Trofimovich).\n\nChanges in release 0.31.1:\n* ADMIN: The neon website has moved to https://notroj.github.io/neon/\n* Restore ne_md5_read_ctx() in OpenSSL build.\n* Fix gcc warnings on Ubuntu (Jan-Marek Glogowski).\n* Fix various spelling mistakes in docs and headers (thanks to FOSSIES).\n* Fix ne_asctime_parse() (Eugenij-W).\n* Fix build with LibreSSL (Juan RP).\n\nChanges in release 0.31.0:\n* Interface changes:\n - none, API and ABI backwards-compatible with 0.27.x and later\n* New interfaces and features:\n - add more gcc \"nonnull\" attributes to ne_request_* functions.\n - for OpenSSL builds, ne_md5 code uses the OpenSSL implementation\n - add NE_SESSFLAG_SHAREPOINT session flag which enables workarounds\n   for RFC non-compliance issues in Sharepoint (thanks to\n   Jan-Marek Glogowski and Giuseppe Castagno)\n - ne_uri.h: add ne_path_escapef() in support of above\n - ne_207.h: add ne_207_set_flags() likewise in support of above\n* API clarification:\n - ne_version_match() behaviour now matches actual 0.27+ ABI history\n* Bug fixes:\n - fixes for OpenSSL 1.1.1 and TLSv1.3 support\n - fix crash with GnuTLS in client cert support (Henrik Holst)\n - fix possible crash in ne_set_request_flag()\n - fix build with libxml2 2.9.10 and later\n - fix handling lock timeouts >LONG_MAX (Giuseppe Castagno)\n\nChanges in release 0.30.2:\n* Add support for OpenSSL 1.1.x (Kurt Roeckx).\n* Fix PKCS#11 support under GnuTLS 3.x.\n - PKCS#11 API no longer supported with GnuTLS 2.x\n\nChanges in release 0.30.1:\n* Fix memory leak with GnuTLS (Werner Baumann, Patrick Ohly).\n* Fix possible crash after DNS lookup errors on Windows (Olivier Goffart).\n* Don't fail if the SSL cert changes between connections with OpenSSL,\n  behaviour now matches that with GnuTLS.\n* Fix PKCS#11 support under OpenSSL with TLS 1.2.\n* Fix static linking with pkg-config file (Alan H).\n\nChanges in release 0.30.0:\n* Interface changes:\n - none, API and ABI backwards-compatible with 0.27.x and later\n* New interfaces and features:\n - ne_ssl.h: added ne_ssl_clicert_import, ne_ssl_context_get_flag\n - ne_session.h: added ne_set_addrlist2\n - ne_socket.h: added ne_addr_canonical\n - ne_auth.h: added NE_AUTH_GSSAPI_ONLY, NE_AUTH_SSPI (Nathanael Rensen)\n - ne_basic.h: added NE_CAP_EXT_MKCOL options test\n - ne_request.h: support chunked bodies with negative length passed to\n   ne_set_request_body_provider (Julien Reichel)\n* Bug fixes:\n - ne_path_escape: fix excessive memory allocation (Pierre Crokaert)\n - SSPI auth: use canonical server hostname, clear SSPI context after\n   successful auth (Nathanael Rensen)\n - build fixes for Open Watcom compiler (NormW)\n - fix Win32 error code handling for local ne_sock_prebind bind failure\n - Win32: support LFS, thread-safe OpenSSL (Diego Santa Cruz)\n - GnuTLS: fix GnuTLS 3.x support (Matthias Petschick, Bartosz Brachaczek)\n\nChanges in release 0.29.6:\n* Don't abort SSL handshake with GnuTLS if a client cert is requested\n  but none is configured/available (thanks to Patrick Ohly)\n* Fix the method string passed to create_request hooks to have the same\n  lifetime as the request object (Patrick Ohly)\n* Docs updates.\n\nChanges in release 0.29.5:\n* Fix GnuTLS handshakes failures with 'TLS warning alert' (Bryan Cain)\n* Further fix for SSPI support on Win32 (Danil Shopyrin)\n\nChanges in release 0.29.4:\n* Fix SNI support (Tobias Gruetzmacher)\n* Fix possible Solaris linker errors if building static library\n* Win32: Fix Kerberos authentication support with SSPI (Danil Shopyrin)\n* Fix error handling when pulling a request body from an file\n  (thanks to Lou Montulli)\n* Fix ne_request_dispatch() return value for SOCKS proxy failure cases\n* Tighten SSL cert ID checks to deny a wildcard match against an IP address\n\nChanges in release 0.29.3:\n* Change ne_sock_close() to no longer wait for SSL closure alert:\n - fixes possible hang with IIS servers when closing SSL connection\n - this reverts the behaviour with OpenSSL to match 0.28.x, and\n   changes the behaviour with GnuTLS to match that with OpenSSL\n* Fix memory leak with GnuTLS\n* API clarification in ne_sock_close():\n - SSL closure handling now documented\n - return value semantics fixed to describe the implementation\n\nChanges in release 0.29.2:\n* Fix spurious 'certificate verify failed' errors with OpenSSL (Tom C)\n* Fix unnecessary re-authentication with SSPI (Danil Shopyrin)\n\nChanges in release 0.29.1:\n* Fixes for (Unix) NTLM implementation:\n - fix handling of session timeout (Kai Sommerfeld)\n - fix possible crash (basic@mozdev.org)\n* Fix unnecessary re-authentication with SSPI (Danil Shopyrin)\n* Build fixes for Win32:\n  - fix use of socklen_t with recent SDKs (Stefan Kung)\n  - fix USE_GETADDRINFO on Win2K (Kai Sommerfeld)\n* Fix build with versions of GnuTLS older than 2.8.0.\n\nChanges in release 0.29.0:\n* Interface changes:\n - none, API and ABI backwards-compatible with 0.28.x and 0.27.x\n* New interfaces and features:\n - added NTLM auth support for Unix builds (Kai Sommerfeld, Daniel Stenberg)\n - ne_auth.h: added NE_AUTH_GSSAPI and NE_AUTH_NTLM auth protocol codes\n - added ne_acl3744.h, updated WebDAV ACL support (Henrik Holst)\n - added built-in SOCKS v4/v4a/v5 support: ne_socket.h:ne_sock_proxy(),       \n   and ne_session.h:ne_session_socks_proxy()\n - added support for system-default proxies: ne_session_system_proxy(),\n   implemented using libproxy where available\n - ne_session.h: added NE_SESSFLAG_EXPECT100 session flag, SSL verification\n   failure bits extended by NE_SSL_BADCHAIN and NE_SSL_REVOKED, better \n   handling of failures within the cert chain (thanks to Ludwig Nussel)\n - ne_utils.h: added feature code NE_FEATURE_SYSPROXY\n - ne_socket.h: ne_sock_writev() (Julien Reichel), ne_sock_set_error(),\n   ne_iaddr_raw(), ne_iaddr_parse()\n - ne_string.h: ne_buffer_qappend(), ne_strnqdup()\n* Deprecated interfaces:\n - ne_acl.h is obsoleted by ne_acl3744.h (but is still present)\n - obsolete feature \"NE_FEATURE_SOCKS\" now never marked present\n* Other changes:\n - fix handling of \"stale\" flag in RFC2069-style Digest auth challenge\n - ne_free() implemented as a function on Win32 (thanks to Helge Hess)\n - symbol versioning used for new symbols, where supported\n - ensure SSL connections are closed cleanly with OpenSSL\n - fix build with OpenSSL 1.0 beta\n - updated Polish (pl) translation (Arfrever Frehtes Taifersar Arahesis)\n\nChanges in release 0.28.6:\n* SECURITY (CVE-2009-2473): Fix \"billion laughs\" attack against expat;\n  could allow a Denial of Service attack by a malicious server.\n* SECURITY (CVE-2009-2474): Fix handling of an embedded NUL byte in\n  a certificate subject name with OpenSSL; could allow an undetected\n  MITM attack against an SSL server if a trusted CA issues such a cert.\n\nChanges in release 0.28.5:\n* Enable support for X.509v1 CA certificates in GnuTLS.\n* Fix handling of EINTR in connect() calls.\n* Fix use of builds with SOCK_CLOEXEC support on older Linux kernels.\n\nChanges in release 0.28.4:\n* Fix ne_forget_auth (Kai Sommerfeld)\n* GnuTLS support fixes:\n - fix handling of PKCS#12 client certs with multiple certs or keys\n - fix crash with OpenPGP certificate\n - use pkg-config data in configure, in preference to libgnutls-config\n* Add PKCS#11 support for OpenSSL builds (where pakchois is available)\n* Fix small memory leak in PKCS#11 code.\n* Fix build on Haiku (scott mc)\n\nChanges in release 0.28.3:\n* SECURITY (CVE-2008-3746): Fix potential NULL pointer dereference in\n  Digest domain parameter support; could allow a DoS by a malicious server\n* Fix parsing of *-Authenticate response header with LWS after quoted value\n* Fix ne_set_progress(, NULL, ) to match pre-0.27 behaviour (and not crash)\n* Fix to disable Nagle on Win32 with newer toolchain (thanks to Stefan Kng)\n* Fix build on Netware (Guenter Knauf)\n* Document existing ne_uri_parse() API postcondition and ne_uri_resolve()\n  pre/postconditions regarding the ->path field in ne_uri structures \n* Mark ne_{,buffer_}concat with sentinel attribute for GCC >= 4.\n* Distinguish the error message for an SSL handshake which fails after a \n client cert was requested.\n* Compile with PIC flags by default even for static library builds\n\nChanges in release 0.28.2:\n* Support \"Proxy-Connection: Keep-Alive\" for compatibility with HTTP/1.0\n proxies which require persistent connections for NTLM authentication\n* Fix an fd leak in ne_ssl_{,cli}cert_read (GnuTLS only)\n* Enable fast initialization in GnuTLS.\n\nChanges in release 0.28.1:\n* Fix Win32 build\n* Fix build on SCO OpenServer 5.0.x (thanks to Nico Kadel-Garcia)\n* Fix handling of Digest domain parameter values without a trailing slash\n* Fix build against apr-util's bundled libexpat.la in Subversion\n* Add --without-pakchois to configure (Arfrever Frehtes Taifersar Arahesis)\n* zh message catalog renamed to zh_CN, translation updated (Dongsheng Song)\n\nChanges in release 0.28.0:\n* Interface changes:\n - none, API and ABI backwards-compatible with 0.27.x\n* New interfaces:\n - ne_pkcs11.h: added basic PKCS#11 support (requires GnuTLS and pakchois)\n - ne_auth.h: added NE_AUTH_ALL and NE_AUTH_DEFAULT constants\n - ne_socket.h: added ne_sock_peer(), ne_sock_prebind(), ne_sock_cipher()\n - ne_session.h: NE_SESSFLAG_TLSSNI flag added; TLS SNI support is enabled\n   by default, where supported; ne_set_localaddr() added\n - ne_request.h: added close_conn hooks (Robert J. van der Boon)\n - ne_basic.h: added ne_options2()\n* Other changes:\n - add Polish (pl) translation (Arfrever Frehtes Taifersar Arahesis)\n - add support for the 'domain' parameter in Digest authentication\n - fix fd leak in ne_sock_connect() error path (Andrew Teirney)\n - the FD_CLOEXEC flag is set on socket fds\n - fix timezone handling in ne_dates for more platforms (Alessandro Vesely)\n - fix ne_simple_propfind() to print XML namespaces in flat property values\n - fix ne_get_range() for unspecified end-range case (Henrik Holst)\n - fix ne_strclean() to be locale-independent and avoid possible Win32 crash\n - fix ne_get_error() to not \"clean\" localized error strings\n - fix ne_ssl_clicert_read() to fail for client certs missing cert or key\n - Win32: fix build with VS 2008 (Stefan Kueng)\n - Win32: fix neon.mak to not double-quote $(MAKE) (Henrik Holst)\n - improve strength of Digest cnonces in GnuTLS builds\n\nChanges in release 0.27.2:\n* Fix crash in GSSAPI Negotiate response header verification (regression\n  since 0.26.x)\n\nChanges in release 0.27.1:\n* Fix regression in response progress counter for notifier/progress callbacks\n* Fix interface description for ne_set_notifier() callback; sr.total\n  is set to -1 not 0 for an indeterminate response length\n\nChanges in release 0.27.0:\n* New interfaces:\n - ne_session.h: ne_fill_proxy_uri() retrieves configured proxy,\n   ne_hook_post_headers() adds a hook after response headers are read,\n   ne_set_connect_timeout() sets session connection timeout,\n   NE_SESSFLAG_RFC4918, NE_SESSFLAG_CONNAUTH flags added\n - ne_socket.h: ne_sock_connect_timeout() sets connection timeout,\n   ne_iaddr_reverse() performs reverse DNS lookup\n - ne_string.h: ne_buffer_snprintf() prints to a buffer object\n - ne_xml.h: ne_xml_resolve_nspace() resolves namespace prefixes\n* Interface changes:\n - ne_set_notifier() replaces ne_set_status(); finer-grained and type-safe\n   connection status information now provided; obsoletes ne_set_progress()\n - ne_xml_dispatch_request() now only invokes the XML parser for \n   response entities with an XML content-type, following RFC 3023 rules\n - ne_acl_set() now takes a \"const\" entries array\n - LFS compatibility functions *64 removed: all functions taking an\n   off_t now take an ne_off_t which is off64_t for LFS builds\n* GnuTLS support now mostly feature-complete with OpenSSL support:\n - greatly improved SSL distinguished name handling with GnuTLS >= 1.7.8\n* Other changes:\n - descriptive error messages for authentication failures\n - SSPI support uses canonical DNS server name (Yves Martin)\n - fixes for handling of \"stale\" parameter in Digest authentication\n - added support for URIs in SSL server certificate subjectAltName field\n - fix compiler warnings with expat 2.x\n - fix handling of \"Transfer-Encoding: identity\" responses from privoxy\n\nChanges in release 0.26.4:\n* Fix Negotiate Authentication-Info response header verification with GSSAPI\n* Fix multiple handlers with ne_add_{server,proxy}_auth (Werner Baumann)\n* Fix SSPI build with some versions of MinGW (Gisle Vanem)\n* Fix for SSPI segfault in response header verification (Mike DiCuccio)\n* Fix error strings for CONNECT SSL proxy tunnel request failure\n* Fix install-nls for VPATH builds (Hans Meine)\n* Fix use of unencrypted client certs with GnuTLS\n* Fix ne_lock* If: header insertion to use CRLF-terminated headers\n* Fix test suite failures on QNX by working around send() length limit\n* Fix handling of POSIX strerror_r failure case in ne_strerror\n* Fix alignment issues in test suite MD5 code\n\nChanges in release 0.26.3:\n* Fix buffer under-read in URI parser (Laszlo Boszormenyi, CVE-2007-0157)\n* Fix regression in handling of \"attempt\" argument passed to auth callbacks;\n  ensure the value only increments for each invocation of the callback\n* Fix handling of \"nextnonce\" parameter in Digest authentication\n\nChanges in release 0.26.2:\n* Fix error reported for LOCK responses lacking a Lock-Token header.\n* Use Libs.private in neon.pc for newer versions of pkg-config.\n* Build fix for platforms without libintl.h.\n* Build fixes for MinGW. (Matthias Miller)\n* Build fix for h_errno detection on HP-UX 10. (Albert Chin)\n* Win32: enable debugging; build fixes with some SDKs. (Kiyo Kelvin Lee)\n\nChanges in release 0.26.1:\n* Build fixes for Win32 (D.J. Heap) and OS X.\n* Add Simplified Chinese translation (Dongsheng Song).\n\nChanges in release 0.26.0:\n* Added internationalization support:\n - ne_i18n.h exposes ne_i18n_init(), a process-global initializer\n   which may be required for some applications\n - (partial) message catalogs for cs, de, fr, ja, nn, ru and tr\n - NE_FEATURE_I18N feature code added to indicate support\n* Added support for GnuTLS (thanks to Aleix Conchillo Flaque):\n - pass --with-ssl=gnutls to configure; GnuTLS >= 1.0.22 required\n - use --with-ca-bundle to specify a default SSL CA root bundle\n - some remaining issues with PKCS#12 certs in current GnuTLS releases,\n   distinguished name handling is sub-standard relative to OpenSSL\n* Changes and additions to URI support:\n - ne_uri structure: add query, fragment fields; authinfo renamed\n   to userinfo\n - ne_uri_parse() now takes a URI-reference as input rather than \n   the previous pseudo-URI syntax; the query and fragment components\n   are now parsed out.  Many malformed URIs are now rejected\n - ne_uri_unparse() changed to respect the new fields\n - ne_uri_resolve(): new function; resolves relative URI references\n - ne_uri_copy(): new function, copies a URI structure\n* Changed results callbacks for ne_lock_discover, PROPFIND interfaces:\n - take URI as parsed ne_uri * structure rather than char *\n* Added functions which give control over authentication protocol use:\n - ne_add_server_auth(), ne_add_proxy_auth()\n* Added ne_unhook_* functions to remove hooks\n* Added ne_set_session_flags()/ne_get_session_flags() functions:\n - flags to disable persistent connection support, enable \"ICY\"\n   protocol support, and to disable SSLv2 protocol support.\n - replaces ne_set_persist()\n* Added ne_set_request_flags()/ne_get_request_flags() functions:\n - flags to enable 100-continue support, mark requests as non-idempotent\n - replaces ne_set_request_expect100()\n* Change ne_md5.h interface to make struct ne_md5_ctx opaque:\n - added ne_md5_create_ctx(), ne_md5_destroy_ctx(), ne_md5_reset_ctx(),\n   ne_md5_finish_ascii(); removed ne_md5_init_ctx()\n - fix alignment issues which could cause crashes in Digest code\n* Fixed ne_get_range(), added ne_get_range64() (thanks to Lennart Poettering)\n* Removed NE_FREE() macro from ne_alloc.h\n* Added ne_strcasecmp(), ne_strncasecmp(), ne_tolower() functions\n  to ne_string.h - locale-independent string comparison\n* Changed ne_sock_init()/ne_sock_exit() such that ne_sock_exit() \n  only has effect once called an equal number of times to _init().\n* Added \"--enable-threadsafe-ssl=posix\" configure flag, to enable\n  thread-safe SSL support using POSIX threads in OpenSSL/GnuTLS\n - NE_FEATURE_TS_SSL feature code added to indicate support\n* The manual is now licensed under the GPL rather than the GFDL\n\nChanges in release 0.25.5:\n* ne_ssl_clicert_decrypt(): catch and fail to load a client cert\n  with mismatched key/cert pair.\n* Fix build issue on AIX 5.1.\n* Fix warnings if built against OpenSSL >= 0.9.8.\n* Win32: fix issues in SSPI implementation (Stefan Kng).\n\nChanges in release 0.25.4:\n* GSSAPI fixes for non-MIT implementations (Mikhail Teterin).\n* Fix ne_print_request_header() et al to use 8K buffer size on all\n platforms (fixes issue with long Destination: URLs on Win32).\n* Win32 build fix for !USE_GETADDRINFO configuration.\n* Documentation updates.\n\nChanges in release 0.25.3:\n* ne_lock() and ne_unlock(): fix cases where NE_ERROR would be returned \n  instead of e.g. NE_AUTH on auth failure.\n* Prevent use of poll() on Darwin.\n* Fix gethostbyname-based resolver on LP64 platforms (Matthew Sanderson).\n\nChanges in release 0.25.2:\n* Really fix the Win32 build.\n\nChanges in release 0.25.1:\n* ne_get_content_type(): fix cases where the charset field was not set\n  to NULL after successful return (Johannes Schneider)\n* Compressed response handling fixes:\n - fix double invocation of reader callback with len=0\n - fix cases where the reader callback return value was ignored\n* Cache the new SSL session if the old one was expired (Robert Eiglmaier)\n* Win32: fix build issues.\n\nChanges in release 0.25.0:\n* New interfaces:\n - ne_get_response_header() replaces ne_add_response_header_handler\n - ne_read_response_to_fd() and ne_discard_response() for use with\n   ne_begin_request/ne_end_request style response handling\n - ne_xmlreq.h: ne_xml_parse_response() and ne_xml_dispatch_request()\n - ne_has_support() for feature detection, replaces ne_support_ssl()\n - ne_set_addrlist() can be used to bypass normal DNS hostname resolver\n - ne_buffer_czappend(), convenience wrapper for ne_buffer_append.\n - ne_iaddr_typeof() returns type of a socket object\n - ne_get_content_type() replaces ne_content_type_handler()\n - ne_set_request_expect100() replaces ne_set_expect100()\n* New interfaces on LFS systems for large file support:\n - ne_set_request_body_fd64() call for using an fd opened using O_LARGEFILE\n - ne_set_request_body_provider64(), takes an off64_t length argument\n* Interface changes:\n - ne_set_request_body_fd takes offset and length arguments and returns void\n - ne_set_request_body_provider takes length as off_t rather than size_t;\n   provider callbacks now MUST set session error string if returning an error\n - response body reader callback returns an integer and can abort the response\n - ne_decompress_destroy() returns void; errors are caught earlier\n - ne_xml_failed() replaces ne_xml_valid(), with different return value logic\n - ne_xml_parse() can return an error; ne_xml_parse_v() aborts the response if \n   the parse either fails or is aborted by a handler returning NE_XML_ABORT\n - ne_path_escape() now escapes all but unreserved characters\n - ne_ssl_clicert_name() and ne_ssl_cert_identity() clarified to return UTF-8\n - ne_ssl_clicert_name() clicert object argument is now const\n - ne_uri_parse()/ne_uri_free() memory handling clarified\n - removed the buffer length requirement for ne_read_response_block()\n* Bug fixes:\n - properly handle multiple Authentication challenges per request\n - fixes and improvements to the Negotiate auth implementation\n - handle proxies which send a 401 auth challenge to a CONNECT request\n - XML: handle the UTF-8 BOM even if the underlying parser does not\n - Win32: Fix timezone handling (Jiang Lei)\n - ne_lock_refresh() works and will update timeout of passed-in lock\n - persistent connection timeout handling fixes for CygWin et al\n - impose hard limit of 1024 props per resource in ne_props.h response parsing\n* New platform-specific features:\n - Win32: Negotiate/NTLM support using SSPI (Vladimir Berezniker)\n - Win32: Add IPv6 support using ENABLE_IPV6 neon.mak flag (Kai Sommerfeld)\n* Removed features:\n - the cookies interface has been removed\n - removed functions: ne_service_lookup(), ne_put_if_unmodified()\n - \"qop=auth-int\" support removed from Digest auth implementation\n* Default XML parser search changed to check for expat before libxml2.\n\nChanges in release 0.24.7:\n* Compression interface fixes:\n - fix issues handling content decoding and request retries from\n authentication challenges (Justin Erenkrantz)\n - fix places where reader callback would receive spurious size=0 calls\n - fix to pass user-supplied userdata to user-supplied acceptance callback\n* Fix for RFC2617-style digest authentication (Hideaki Takahashi).\n* Fix to pick up gethostbyname() on QNX 6.2.\n\nChanges in release 0.24.6:\n* SECURITY (CVE CAN-2004-0398): Fix sscanf overflow in ne_rfc1036_parse,\n thanks to Stefan Esser.\n* Link libneon against libexpat during Subversion build using bundled neon.\n* Win32 build script update (Jon Foster).\n\nChanges in release 0.24.5:\n* SECURITY (CVE CAN-2004-0179): Fix format string vulnerabilities in\n XML/207 response handling, reported by greuff@void.at.\n* Performance fix: avoid seeding the SSL PRNG if not creating an SSL socket.\n* ne_ssl_readable_dname() is now defined to return UTF-8 strings.\n* Fix case where gssapi/gssapi_generic.h was included but not present.\n* Fix ne_utils.c build on platforms where zlib does \"#define const\".\n* Fix use of ne_proppatch_operation with some C++ compilers.\n* Update libtool for fix to --enable-shared on Darwin.\n* BeOS: check for gethostbyname in -lbind (David Reid).\n\nChanges in release 0.24.4:\n* Ignore unclean SSL closure when response body is delimited by EOF\n (\"Could not read response body: Secure connection truncated\" errors\n with some buggy SSL servers).\n* Fix test/ssl.c syntax errors with C89 compilers (Radu Greab).\n\nChanges in release 0.24.3:\n* Respect configure's --datadir argument (Max Bowsher).\n* Fix build on Windows when OpenSSL is not used.\n* Fix use of SSLv2 (spurious \"Server did not present certificate\" error).\n* When using SSL via a proxy, prevent leaking server auth credentials\n to the proxy, or proxy auth credentials to the server.\n\nChanges in release 0.24.2:\n* Fix name resolver with some old versions of glibc.\n* Fix problems with configure's \"time_t format string\" detection.\n* Fix problems when a broken Kerberos installation is found.\n* When verifying SSL certificates, check iPaddress names in the\n subjectAltName extension.\n\nChanges in release 0.24.1:\n* Add support for \"GSS-Negotiate\" Kerberos authentication scheme (from\n Risko Gergely and Burjan Gabor).\n* Disable Nagle to improve performance of small requests (thanks to\n Jim Whitehead and Teng Xu).\n* Fix compatibility with OpenSSL 0.9.6 (broken in 0.24.0).\n* Fix prototype mismatch in ne_207.c.\n* Define ssize_t from ne_request.h for Win32.\n* Prevent segfault on zlib initialization failures.\n* ne_sock_init does not fail if PRNG could not be seeded.\n* Fix segfault in cookies code (Markus Mueller).\n* Documentation updates.\n\nChanges in release 0.24.0:\n* Major changes to XML interface:\n - have the start-element callback either accept, decline, abort, \n or return a state integer.\n - remove 'struct ne_xml_elm'; callbacks are passed {nspace, name}\n strings along with a state integer.\n - dropped \"collect\", \"strip-leading-whitespace\" modes\n - push responsibility for accumulating cdata onto caller; drop 'cdata'\n argument from end-element callback.\n - don't abort if no handler accepts a particular element, just ignore\n that branch of the tree.\n - dropped support for libxml 1.x and expat < 1.95.0.\n - guarantee that start_element callback is not passed attrs=NULL\n - add ne_xml_doc_encoding() to retrieve encoding of parsed XML document.\n* Major changes to SSL interface:\n - rewrite of interfaces for handling server and client certificates;\n ne_ssl.h: many new functions available.\n - only PKCS#12-encoded client certs are supported.\n - changes to most names of SSL-related functions operating on an\n ne_session, e.g. ne_ssl_load_cert->ne_ssl_trust_cert.\n - client cert provider callback is passed the set of acceptable CA\n names sent by the server\n - the entire chain of certs presented by server is now accessible\n* Remove unused ne_register_progress() from socket layer.\n* Changes to resolver interface: ne_addr_first and _next return const;\n ne_addr_print renamed to ne_iaddr_print; ne_iaddr_make and ne_iaddr_free\n have been added.\n* ne_request_create() now duplicates the method string passed in.\n* ne_redirect_location() will now return NULL in some cases.\n* Split socket creation to ne_sock_create() from ne_sock_connect:\n - should report connect() error messages properly on Win32.\n* Fix several memory leaks in error handling paths.\n* Add a pkg-config file, neon.pc.in.\n\nChanges in release 0.23.9:\n* Fix inability to connect on AIX 4.3.\n* neon-config exports includes needed for OpenSSL given by pkg-config.\n* ne_redirect_location will return NULL if redirect hooks have not\n been registered for the session (Ralf Mattes <rm@fabula.de>).\n\nChanges in release 0.23.8:\n* SECURITY: Prevent control characters from being included in the\n reason_phrase field filled in by ne_parse_statusline(), and in\n the session error string.\n* Disable getaddrinfo() support on HP-UX; fix resolver for HP-UX 11.11.\n* Fix digest auth response verification for >9 responses in session\n (bug manifests as \"Server was not authenticated correctly\" error).\n* On Linux, skip slow lookup for IPv6 addresses when IPv6 support is\n not loaded in kernel (thanks to Daniel Stenberg for this technique).\n* Update to autoconf 2.57 and libtool 1.4.3.\n\nChanges in release 0.23.7:\n* Fix for handling EINTR during write() call (Sergey N Ushakov).\n* When available, use pkg-config to determine compiler flags needed to \n use OpenSSL headers and libraries.\n\nChanges in release 0.23.6:\n* Fixes for error handling in socket layer on Win32 from Johan Lindh\n and Sergey N Ushakov <ushakov@int.com.ru>:\n - meaningful error messages rather than \"No error\"\n - handle persistent connection timeouts properly\n* Fix to use RFC2617-style digest auth when possible (had reverted to \n only using RFC2068-style in 0.16.1).\n* Fix NULL pointer dereference on certain ill-formed PROPFIND responses.\n* Allow ne_sock_init to re-initialize after ne_sock_finish has been called\n (Sergey N Ushakov).\n\nChanges in release 0.23.5:\n* Fix rejection of SSL server certificates which had commonName as\n the least specific attribute in the subject name.\n* Fix to dereference entities (e.g. \"&amp;\") in attribute values with libxml.\n* Fix ne_socket.c build on HP-UX 10.20 (thanks to Branko ibej)\n* Remove misguided insistence on \"secure\" versions of zlib/OpenSSL;\n no checks for zlib version are now performed, only OpenSSL 0.9.6 is\n required.  --with-force-ssl, --with-force-zlib option removed.\n* Add --with-egd[=PATH] option, conditionally enable EGD support; either \n using EGD socket at PATH, or fall back on system defaults.  $EGDSOCKET \n and $HOME/.entropy are no longer used.\n* Add support for `--la-file' argument to neon-config, which prints the\n full path of the installed libneon.la file.\n\nChanges in release 0.23.4:\n* Ignore an unclean SSL shutdown on persistent connection timeout\n (fixing spurious \"Secure connection truncated\" errors).\n* Fix a segfault on second and subsequent requests using a given\n session, when the first fails with NE_LOOKUP.\n* Fix configure for gcc installations which produce warnings by default\n (such as gcc on hppa2.0n-hp-hpux11.00 using native as)\n\nChanges in release 0.23.3:\n* Further build fixes for Win32 (Blair Zajac).\n* Another fix for use of SSL against Tomcat 3.2.\n\nChanges in release 0.23.2:\n* Build fix for Win32 (Blair Zajac).\n\nChanges in release 0.23.1:\n* Identify as correct version, not 0.22.\n\nChanges in release 0.23.0:\n* Improved address resolver (ne_addr_*) replacing ne_name_lookup():\n - use getaddrinfo() if found; include support for IPv6 (based on work\n by Noriaki Takamiya <takamiya@po.ntts.co.jp>)\n* For a hostname with multiple addresses, each address is tried in turn\n until a connection is made.\n* Support for seeding OpenSSL's PRNG via $EGDSOCKET or $HOME/.entropy,\n to enable SSL on platforms which lack a /dev/random device.\n* RFC2818 compliance for certificate identity checks in SSL:\n - use `dNSname' values in subjectAltName extension if present\n - hostname comparison fixed to not be case-sensitive\n* Fix interop with buggy SSL implementation in Tomcat 3.2.\n* Added NE_DBG_SSL debug channel.\n* ne_strerror changed to return the passed-in buffer.\n* Added ne_strnzcpy macro to ne_string.h.\n* Win32 build fixes, improvements, and documentation updates, from \n Blair Zajac <blair@orcaware.com>.\n* Fix ne_sock_init so SIGPIPE signals are ignored even if SSL library\n initialization fails (e.g. platforms without /dev/random).\n* Added reference documentation:\n - ne_sock_init, ne_addr_*.\n\nChanges in release 0.22.0:\n* Remove the const qualifier from the reason_phrase field in ne_status.\n - ne_parse_statusline() now strdup's the reason_phrase\n* Remove the status_line argument from ne_207_end_propstat and _end_response\n* Change ne_session_create, ne_session_proxy, ne_sock_connect, and the \n 'port' field of the ne_uri structure to use an unsigned int for port numbers\n* ne_uri_defaultport returns unsigned and '0' on an unknown port (not -1).\n* Changes to hooks interface:\n - pass an ne_request pointer to per-request hooks\n - replace \"accessor\" hooks with ne_{get,set}_{request,session}_private\n* Authentication changes:\n - the hooks changes fix a segfault if auth is enabled for an SSL session\n through a proxy server\n - fix ne_forget_auth segfault if either proxy or server auth are not used\n* Improvements to persistent connection retry logic and error handling \n in request code; fixing some cases where some errors where incorrectly\n treated as a persistent connection timeout\n - a TCP RST at the appropriate time is now treated as a persistent \n connection timeout.\n - handle persistent connection timeouts on SSL connections\n* Changes to SSL support:\n - improved error handling\n - OpenSSL 0.9.6f or later is required for security fixes and functional\n correctness; 0.9.6 or later required for functional correctness\n - use --with-force-ssl to override OpenSSL version check\n - fix for proxy CONNECT tunnelling with some proxies (e.g. Traffic-Server)\n - fix potential segfault if client cert. provider callback is used\n - fix to use supplied password callback for PEM-encoded client certificates\n (Daniel Berlin <dberlin@dberlin.org>)\n* strerror_r is used if available for thread-safe error handling.\n* Remove ne_read_file().\n* ne_version_match replaces ne_version_minimum (semantics changed slightly).\n* XML request bodies use a content-type of \"application/xml\" now; \n applications can use NE_XML_MEDIA_TYPE from ne_xml.h\n* Fix decompress code on big-endian or 64-bit platforms.\n* Fix to build on Darwin 6 (aka Mac OS X 10.2) (Wilfredo Snchez,\n <wsanchez@mit.edu>)\n* Win32 changes:\n - remove conflict between OpenSSL's X509_NAME and recent versions of\n the Platform SDK (Branko ibej)\n - fix inverted debug/non-debug build logic (Branko ibej)\n - add NODAV and OPENSSL_STATIC flags to neon.mak (Gerald Richter)\n\nChanges in release 0.21.3:\n* Fix segfault if using proxy server with SSL session and server\n certificate verification fails.\n* Fix leak of proxy hostname once per session (if a proxy is used).\n* Add --with-libs configure argument; e.g. --with-libs=/usr/local picks\n up any support libraries in /usr/local/{lib,include}\n\nChanges in release 0.21.2:\n* Fix 'make install' for VPATH builds.\n* Use $(mandir) for installing man pages (Rodney Dawes).\n* Follow some simple (yet illegal) relativeURI redirects.\n* Always build ne_compress.obj in Win32 build (Branko ibej).\n* Fix decompression logic bug (Justin Erenkrantz <jerenkrantz@apache.org>)\n (could give a decompress failure for particular responses)\n* Fix ne_proppatch() to submit lock tokens for available locks.\n* More optimisation of ne_sock_readline.\n\nChanges in release 0.21.1:\n* Don't include default SSL port in Host request header, which can\n help interoperability with misbehaving servers (thanks to Rodney Dawes\n <dobey@ximian.com>).\n* Don't give a \"truncated response\" error from ne_decompress_destroy if\n the acceptance function returns non-zero.\n* Fix for Win32 build (Sander Striker <striker@apache.org>).\n* Fix for cookie name/value being free()d (thanks to Dan Mullen).\n* Optimisation of ne_sock_readline.\n\nChanges in release 0.21.0:\n* Socket layer implements read buffering; efficiency and performance \n improvement. Based on work by Jeff Johnson <jbj@redhat.com>\n* Cleanup of socket interface:\n - renamed everything, s/sock_/ne_sock_/, s/SOCK_/NE_SOCK_/\n - removed unused and inappropriate interfaces.\n - renaming done by Olof Oberg <mill@pedgr571.sn.umu.se>\n - see src/ChangeLog for the gory details.\n* Fix typoed 'ne_destroy_fn' typedef (Olof Oberg).\n* Support OpenSSL/ENGINE branch.\n* Bogus ne_utf8_encode/decode functions removed.\n* ne_base64() moved to ne_string.[ch].\n* ne_token drops 'quotes' parameter; ne_qtoken added.\n* ne_buffer_create_sized renamed to ne_buffer_ncreate.\n* ne_xml_get_attr takes extra arguments and can resolve namespaces.\n* ne_accept_response function type takes const ne_status pointer.\n* Drop support for automatically following redirects:\n - ne_redirect_register just takes a session pointer\n - ne_redirect_location returns an ne_uri pointer\n* configure changes: --with-ssl and --with-socks no longer take a directory\n argument.  To use SOCKS or SSL libraries/headers in non-system locations, \n use ./configure CPPFLAGS=-I/... LDFLAGS=-L/... \n* Reference documentation included for most of ne_alloc.h and ne_string.h,\n and parts of ne_session.h and ne_request.h.\n - see installed man pages, HTML documentation.\n\nChanges in release 0.20.0:\n* Major changes to DAV lock handling interface (ne_locks.h):\n - struct ne_lock uses a full URI structure to identify locked resource\n - ne_lock() requires that owner/token fields are malloc-allocated (or NULL)\n on entry\n - introduce a \"lock store\" type, ne_lock_store, to replace the lock session;\n accessor functions all renamed to ne_lockstore_*.\n - ne_lock_iterate replaced with a first/next \"cursor\"-style interface\n - If: headers use an absoluteURI (RFC2518 compliance fix).\n - fix for handling shared locks on DAV servers which return many active locks\n in the LOCK response (thanks to Keith Wannamaker)\n* Moved URI/path manipulation functions under ne_* namespace (ne_uri.h):\n - path handling functions renamed to ne_path_*\n - URI structure handling to ne_uri_*; struct uri becomes ne_uri.\n - ne_uri_parse doesn't take a 'defaults' parameter any more\n - if URI port is unspecified, ne_uri_parse sets port to 0 not -1.\n - added ne_uri_unparse and ne_uri_defaultport functions.\n* New 'ne_fill_server_uri' function to initialize a URI structure with\n the server details for a given session (useful with locks interface).\n* ne_decompress_{reader,destroy} are defined as passthrough-functions\n if zlib support is not enabled.\n* API change: ne_ssl_provide_fn returns void not int.\n* Added NE_SSL_FAILMASK for verify failure sanity check.\n* Removed return codes NE_SERVERAUTH and and NE_AUTHPROXY; correct\n documentation, NE_PROXYAUTH is given for proxy auth failure.\n* Require zlib >= 1.1.4 to avoid possible vulnerability in earlier versions.\n See http://www.gzip.org/zlib/advisory-2002-03-11.txt for more details.\n (version check can be skipped by passing --with-force-zlib to configure)\n* New 'ne_ssl_readable_dname' function to create a human-readable string\n from an X509 distinguished name.\n* Fix support for newer versions of libxml2 (thanks to Jon Trowbridge \n <trow@gnu.org>).\n* Fix corruption of reason_phrase in status object returned by\n ne_propset_status.\n* More lenient handling of whitespace in response headers.\n* ne_content_type_handler will give a charset of \"ISO-8859-1\" if no charset\n parameter is specified for a text/* media type (as per RFC2616).\n* Miscellaneous cleanups and fixes (Jeff Johnson <jbj@redhat.com>).\n\nChanges in release 0.19.4:\n* Support bundled build of expat 1.95.x (Branko ibej).\n\nChanges in release 0.19.3:\n* For platforms lacking snprintf or vsnprintf in libc, require trio.\n* Add NE_FMT_OFF_T to fix Win32 build (Dan Berlin, Branko ibej).\n* Fix SSL support in Win32 build (Branko ibej).\n\nChanges in release 0.19.2:\n* Fix non-SSL build broken in 0.19.1.\n* Working SOCKSv5 support (thanks to Torsten Kalix <torsten.kalix@bredex.de>)\n\nChanges in release 0.19.1:\n* Add missing stubs for ne_ssl_* functions for non-SSL build.\n* Fix some error messages in new SSL code.\n\nChanges in release 0.19.0:\n* Major API change: ne_session_create now takes (scheme, hostname, port) \n arguments: a session is clarified to be \"a group of requests to a\n certain server\".\n - removal of ne_session_server, ne_set_secure, and ne_set_proxy_decider\n - ne_session_proxy returns void.\n - DNS lookups are delayed until request dispatch time.\n* Significant improvements to TLS/SSL support:\n - SSL is enabled if scheme passed to ne_session_create is \"https\"\n - new interfaces to load CA certs and to load SSL library's bundled CA certs\n - add server cert verification callback.  An SSL connection to a server\n with an unknown CA will now fail unless a verification callback is used.\n - enable SSL session caching (performance improvement)\n - support for wildcard server certs where commonName is \"*.example.com\".\n - thanks to Tommi Komulainen for the contribution of code from mutt's\n IMAP/SSL implementation under the LGPL, from which bits of this were derived.\n* Improved SSL client certificate support:\n - far simpler interface, all done at ne_session.h level.\n - supports PKCS#12 and PEM-encoded certificates.\n - optional callback for only providing client when demanded by server.\n* Support for TLS upgrade is removed, since it isn't useful.\n* If NEON_SSL is defined, API extensions are available to:\n - allow access to the SSL_CTX * to adjust session SSL options\n - retrieve the server certificate (X509 *)\n* Decompress fixes:\n - fix potential segfault in ne_decompress_destroy\n - check the CRC of the deflated output (and fail if it doesn't match)\n - fail appropriately on truncated responses, and trailing bytes in response. \n* Added ne_set_read_timeout to use configurable timeout on socket reads.\n* Malformed response headers will be ignored rather than failing the request.\n* ne_set_error takes printf-style vararg.\n* Fixes for ne_get_range and improve error handling. \n* Functions which append to an ne_buffer do not return a success value,\n but they do use ne_realloc/ne_malloc under the hood now, so an OOM callback\n will be used (with the usual caveats).\n* XML interface does not strip leading whitespace from cdata by default,\n the NE_XML_STRIPWS flag is available to restore this feature if required.\n* Upgraded to libtool 1.4.2:\n - should fix --enable-shared on Mac OS X 10.1\n* Test suite now contains over one hundred tests.\n\nChanges in release 0.18.5:\n* Removed old neon.dsp, neon.dsw.\n* Update Win32 build to add OpenSSL and zlib support (Branko ibej).\n* Fix ne_compress.c to compile on Win32 (Branko ibej).\n\nChanges in release 0.18.4:\n* Fixes for Content-Type parsing using ne_content_type_handler (Greg Stein)\n - also now parses the charset parameter from header value.\n* Removed ne_concat() function, which didn't work and wasn't used.\n\nChanges in release 0.18.3:\n* Fix parsing lock timeout from server (Arun Garg).\n* Send Timeout headers in LOCK and refresh LOCK requests (Arun Garg).\n* Updated neon.mak and config.hw.in for Win32 build (patch from\n Branko ibej <brane@xbc.nu>).\n* Define XML_BYTE_ORDER for bundled expat build in support macro\n NEON_XML_PARSER().\n\nChanges in release 0.18.2:\n* Fix --with-neon=PATH in support macros.\n* Support DESTDIR in Makefile install targets (patch by\n Pawel Golaszewski <blues@blysk.ds.pg.gda.pl>).\n* Portability fixes:\n - fix configure check for time_t on some platforms (e.g Solaris 2.6).\n - remove expect100_works bitfield in ne_session structure (thanks to \n Yan Periard <yperiard@ems.net>).\n\nChanges in release 0.18.1:\n* Minor fix for authentication: \"attempt\" counter was not reset correctly\n after authentication failed, so subsequent requests would not authenticate\n correctly either.\n* API change: ne_session_destroy returns void (there was no error case).\n* Portability fixes (non-GCC compilers, 64-bit platforms, UnixWare 7)\n* Optimisations in string manipulation routines.\n* config.hw is included in the release tarball again.\n* Improvements in the autoconf support macros:\n - check for neon-config in PATH if --with-neon is not given\n - stop if --with-neon is used, and the check for external neon fails\n - added NEON_WITHOUT_ACL to prevent build of ne_acl.o\n\nChanges in release 0.18.0:\n* API change: authentication callback is passed fixed-size username/password\n buffers, and an 'attempt' counter.  Authentication is retried *forever*\n until either it succeeds, or the callback returns non-zero.\n* API clarifications:\n - ne_propname may have a NULL nspace field, indicating the property has no \n namespace.  This holds for properties returned by the propfind interfaces.\n - added NE_ELM_PROPS_UNUSED as the lowest element number which should\n be used with handlers added to the XML parser returned by \n ne_propfind_get_parser.\n* Fixes and cleanups of lock discovery interface.\n* Fix for short write handling in ne_get() (thanks to rado <dzusto@yahoo.com>).\n* Fix for XML namespace prefix handling where a prefix could be mapped to an \n incorrect URI (e.g. in PROPFINDs against mod_dav with >10 namespaces used)\n* Add '--support <feature>' option to neon-config; the script exits with\n success if given feature is supported. Known features are ssl, dav, zlib.\n* Support for SSL, DAV, zlib is exported by neon.m4 as shell variable \n NEON_SUPPORTS_{SSL,DAV,ZLIB}={yes,no} for bundled and external builds.\n* `neon-config --cflags` won't include -I/usr/include for SSL build.\n* Fix to call progress callbacks while sending request bodies again.\n* Test changes:\n - portability fixes, auth interface and progress tests.\n\nChanges in release 0.17.2:\n* Accept Status-Lines with no reason phrase (Jeremy Elson).\n* Fix handling of persistent connection timeout, and better error\n handling if sending a request fails.\n* Fix crashes in locking code.\n* Return parse error on XML namespace prefix declaration with\n an empty value. Thanks to Julian Reschke.\n* Allow passing property names with NULL namespace to ne_proppatch.\n* Fix for cross-compilation (Mo DeJong).\n* Moved ne_propname definition from ne_207.h to ne_props.h.\n* Test changes:\n - updated for Status-Line parsing changes (Jeremy Elson)\n - better persistent connection tests\n - fixed for --disable-webdav build\n\nChanges in release 0.17.1:\n* Add support for ACL method (Arun Garg <arung@pspl.co.in>),\n see ne_acl.h.\n* Fixes and clean up of libraries exported via `neon-config --libs'\n* Fix timezone handling when parsing dates (on some platforms).\n* Upgrade to autoconf 2.52 and libtool 1.4 (thanks to Mo DeJong).\n* Cleanup/simplification of request dispatching:\n - better handling of error cases, including fix for a possible\n infinite loop when the server closes the connection prematurely.\n* Add '--without-zlib' configure option.\n* Test changes:\n - prettify output; imitate Perl test suite output.\n - add tests for interim 1xx responses, persistent connections, more\n unbounded operations.\n\nChanges in release 0.17.0:\n* Add support for decoding gzip Content-Encoding: see ne_compress.h.\n - built if zlib is found; `neon-config --cflags' will define NEON_ZLIB if so.\n* Rewrite hooks interface to register individual callbacks.\n - inspired by the Apache 2.0/APR hooks interface\n* Register cookies hooks using ne_cookie_register().\n* Clean up configure scripts to enable use of autoconf 2.5x (Mo DeJong).\n* Use new endianess configure macro to allow cross-compiling (Mo DeJong).\n* Fix invalid C code in sock_init() in Win32 build (Mo DeJong).\n* Fix use of signal() on Win32 (Mo DeJong).\n* Workaround libxml 1.x string handling not being UTF-8.\t\n* Test changes:\n - add tests for decompression interface.\n\nChanges in release 0.16.1:\n* Also handle write errors in ne_get_range.\n* Dump request body blocks in debugging mode.\n* Fix ne_shave() causing memory corruption when the result should \n  have been the empty string.\n* Refactor auth header parsing code; more efficient now. \n - fixes digest auth RFC2617-style broken in 0.16.0\n\nChanges in release 0.16.0:\n* API change: ne_copy takes a depth parameter (thanks to Arun Garg, Medha Atre)\n* API change: validate callback to ne_xml also takes a userdata arg.\n* Added 'ne_lock_refresh' for performing lock refresh (Arun Garg).\n* Add SSL support to Win32 build (Peter Boos <PediB@colorfullife.com>)\n  (see INSTALL.win32 for details).  Compile with USE_DAV_LOCKS also.\n* Remove Server header parser for 100-continue support in ne_options.\n  (and remove broken_expect100 from ne_server_capabilities).\n* Set SIGPIPE disposition to \"ignored\" in sock_init().\n* On platforms with setvbuf(), turn off buffering for the debug log \n  stream.\n* Ignore repeated calls to sock_init().\n* Fixes to error handling in ne_get_range.\n* Minor improvements to memory handling in auth code.\n* Fix for start_propstat callback being called with NULL response\n  argument when given invalid XML, causing a segfault in propfind code.\n* Test changes:\n - add regression test for the propfind segfault.\n - handle segfaults better (reap the child, flush the debug log).\n\nChanges in release 0.15.3:\n* Fix --with-expat=DIR build.\n\nChanges in release 0.15.2:\n* Fix Win32 for XML parser changes (Gerald Richter).\n* Substitute versions into config.hw at distribution time.\n* Add date parser for ISO8601-formatted dates as defined by RFC2518, e.g. \n  the creationdate property (Taisuke Yamada <tai@iij.ad.jp>).\n* Fix Y2K bug in RFC1036 date parsing algorithm.\n* Test changes:\n - add tests for date parsing functions.\n\nChanges in release 0.15.1:\n* Win32 update from Gerald Richter <richter@ecos.de>\n - new files neon.mak, INSTALL.win32\n* Fix for ne_socket.h includes (Mo DeJong).\n* More improvements for XML parser selection logic:\n - if parser is required, be sure to fail configure if none is found.\n - added --with-included-expat for bundled expat logic.\n* Rename --enable-debugging to --enable-debug (Mo DeJong).\n - added NEON_DEBUG macro to exported autoconf macros.\n* Call progress callbacks for request bodies.\n* Test changes:\n - check that reading response headers is a bounded operation.\n - use a pipe between child and parent to avoid race condition and \n tedious sleep().\n\nChanges in release 0.15.0:\n* Major API renaming to use ne_/NE_ namespace:\n - http_ to ne_, HTTP_ to NE_, dav_ to ne_, DAV_ to NE_, neon_ to ne_\n - hip_xml_ to ne_xml_, HIP_ELM_ to NE_ELM_, HIP_XML_ -> NE_XML_\n - sbuffer_ to ne_buffer_\n - DEBUG() to NE_DEBUG(), DEBUG_ to NE_DBG_\n* Type renames:\n - http_req to ne_request\n - sbuffer to 'ne_buffer *'\n* Note, 'ne_buffer' is not an implicit pointer type, you must \n  specify the '*' now, e.g. 'ne_buffer *buf = ne_buffer_create();'.\n* ne_buffer is no longer opaque.\n - ne_buffer_data() removed: use buf->data instead.\n - ne_buffer_size() is a macro.\n* Header renames and additions:\n - http_request.h -> ne_request.h\n - Session code split into ne_session.h\n - hip_xml.h -> ne_xml.h, nsocket.h -> ne_socket.h, http_utils.h -> ne_utils.h\n - neon_md5.h -> ne_md5.h, dav_207.h -> ne_207.h\n - http_basic.h and dav_basic.h merged into ne_basic.h\n* New functions:\n - ne_token and ne_shave, to obsolete split_string, shave_string.\n* Removed: ne_get_request_headers().\n* autoconf changes:\n - disable building shared neon library by default.\n - option --enable-libxml is replaced by --with-libxml1 and\n --with-libxml2 to force use of a particular parser.\n* Fix auth code to only take MD5 digests of response body blocks when\n  necessary (thanks to Kai Sommerfeld).\n* Fix alignment bug in MD5 code which could cause SIGBUS on Sparc \n  architectures (Kai Sommerfeld).\n* Rewrite of request body handling:\n - ne_set_request_body_fd replaces _stream, using an int fd rather than\n a FILE *.\n - added ne_set_request_body_provider to give a callback which is called\n to provide request body blocks.\n - removal of 'use_body' hook in favour of 'ne_pull_request_body' function\n to allow hooks to manually read the request body.\n - ne_{put,get,post,put_if_unmodified} all take an integer fd rather than a\n FILE * stream.\n* Test changes:\n - added framework for testing \"over the wire\" (fork a server process)\n - added tests for response message length handling, chunked responses, \n header folding, sending request bodies.\n - start at listing RFC2616 requirements and whether they are met\n or not in test/STATUS.\n - test for MD5 alignment bug on Sparc (thanks to Kai Sommerfeld).\n\nChanges in release 0.14.0:\n* Add C++ inclusion safety to http_auth.h (Kai Sommerfeld).\n* Define ssize_t on Win32. (Kai Sommerfeld).\n* Add C++ inclusion safety to dav_locks.h and ne_alloc.h (thanks to\n  Gregor Bornemann <Gregor.Bornemann@germany.sun.com>).\n* Significant API change to properties code, to allow use of allprop\n  and complex properties:\n - dav_propfind_set_complex and _set_flat are removed.\n - add parameter to dav_propfind_named to take the list of property names \n   to be fetched.\n - new function dav_propfind_set_private to set private callback.\n - all properties not handled by caller are stored as flat properties.\n* Untested: add basic SOCKSv5 support: configure --with-socks.\n - please report success/failure to neon@webdav.org\n* Win32/MSVC build files from Magnus Sirwi <sirwio@hotmail.com>.\n* Fix for expat detection from Shane Mayer <shanemayer42@yahoo.com>.\n* Namespace-protect md5 code and more.\n - md5_* -> ne_md5_*\n - ascii_to_md5 -> ne_ascii_to_md5 (and moved to neon_md5.h)\n* Parse authinfo segment in URIs (Johan Lindh <johan@link-Data.com>).\n - added 'authinfo' field to struct uri.\n* New API: hip_xml_get_attr to retrieve attributes.\n* Store language for properties, access with dav_propset_lang.\n - only if property is defined on the property element itself.\n* Started a simple test suite (test/*).\n - includes some simple HTTP server tests.\n* Remove \"Content-Length: 0\" header for request with no body, fixing\n  interop with Squid 2.3-STABLE1 (thanks to Kai Sommerfeld).\n* http_parse_statusline skips leading whitespace. (Johan Lindh). \n* Partial fix for timezone/date parsing problems.\n\nChanges in release 0.13.0:\n* Fix ne_strndup allocating one byte less than it should (Kai Sommerfeld)\n - if you use uri_parse, this bug may have caused subtle memory corruption \n   in your application. \n* Revert API changes in 0.12: property values are not UTF-8 encoded/decoded\n  internally.  (thanks to Greg Stein)\n* Add another optional argument to NEON_BUNDLED macros, actions to\n  be run if bundled build is *not* selected.\n* API change: added argument to http_add_hooks to register cleanup function\n  for the cookie.\n* Removed dav_lock_unregister in favour of automatic cleanup when session\n  is destroyed.\n* Fixed leaks in redirect code (Kai Sommerfeld).\n* Fixed crashes in hip_xml_destroy (Kai Sommerfeld).\n* Redirects to a different hostname/port/scheme are never followed: the request\n  will fail with HTTP_REDIRECT instead.  Redirect notification callback is \n  only called for *followed* redirects.\n  New API: http_redirect_location() for retrieving location of last redirect.\n* Authentication is now implemented as a hook, independently of http_request.c:\n - API change: removed 'hostname' argument from auth callbacks.\n - API change: you must now include http_auth.h from your application.\n - Also fixes case of using server and proxy authentication simultaneously\n* Added 'http_forget_auth' to clear authentication session.\n* New API: http_session_hook_private for retrieving private per-session cookie \n  for hooks.\n* API change: http_set_request_body_stream has a return error value.\n* API change: http_set_request_body_buffer now takes the buffer length too.\n* New API: caller-pulls interface for reading response body: \n  http_begin_request, http_end_request, http_read_response_block. \n  An alternative to using the (much simpler) http_request_dispatch.\n* Make --disable-webdav build work.\n* New API: dav_propnames for retrieving property names.\n* New API: dav_propfind_get_request to access request object of handler.\n* API change: progress and connection status callbacks implemented at\n  http_request.h level. Socket-level status callbacks removed, progress\n  callbacks made per-socket.\n* Supports new expat (Sam TH <sam@uchicago.edu>)\n* Supports libxml2 (in preference to libxml1).\n* API change: added namespace protection to base64 and dates functions:\n  all have ne_ prefix now.\n* Fixed ranged GETs where a specific range is requested (Johan Lindh \n  <johan@linkdata.se>).\n* Limit number of response header fields to 100.\n* Allow requests for the '*' URI even if a proxy server is in use.\n* libxml: Get useful error messages for parse errors.\n\nChanges in release 0.12.0:\n* Portability fixes to http_request.c and http_auth.c.\n - fixes digest auth on big-endian architectures.\n* Fix warnings from stray tokens after #endif's in uri.h and string_utils.h.\n* Add C++ inclusion safety to http_redirect.h (Kai Sommerfeld \n  <kai.sommerfeld@germany.sun.com>).\n* Make redirects to a different host work (Kai Sommerfeld).\n* Fix reading response bodies when non-chunked and no Content-Length\n  (Kai Sommerfeld).\n* API change: 'http_add_hooks takes a 'const' request object.\n* Fixed memory leaks in session hooks (thanks to Kai Sommerfeld).\n* Fix passing NULL props argument to dav_simple_propfind, to support\n  allprop requests.\n**** MAJOR INTERFACE CHANGE ****\n - URIs passed to http_request_create() are NOT escaped by neon. You \n   MUST do this yourself to remain HTTP compliant, using e.g. \n   uri_abspath_escape. (Kai Sommerfeld)\n* Added --disable-webdav flag to configure, to disable DAV support in\n  the library.  This allows building neon without an XML parser. \n* Corresponding NEON_WITHOUT_WEBDAV macro for use in bundled builds.\n* Fix Makefile dependancies.\n* A bundled neon directory builds or doesn't build automatically\n  (i.e. you recurse into it unconditionally).\n* API clarification:\n - dav_propset_status may return NULL if the server does not return\n   a response for the given property (issue is open for debate).\n* API change up for debate:\n - Property values to dav_proppatch are UTF-8 encoded internally.\n - Property values in dav_propfind_* are UTF-8 decoded internally.\n* API additions: ne_realloc, ne_utf8_encode.\n\nChanges in release 0.11.0:\n* Added SSL client certificate support with 'sock_set_client_cert'.\n - Supports certs in PEM-encoded files.\n - Specify a callback for prompting the user for the password with \n     sock_set_key_prompt.\n* Added 'ne_oom_callback', to register a callback which is used if\n  malloc() returns NULL.  (Mike Rosellini <m@icopyright.com>)\n* Register appropriate callback with libxml to handle <![CDATA blocks\n  as normal character data (fixes PROPFINDs against sharemation.com).\n* Added 'NEON_REQUIRE' macro to declare that you require a neon library\n  of a given minimum version, e.g.  NEON_REQUIRE(0,10) means \"I need \n  neon 0.11 or later\".  The _BUNDLED macros will fall back on the bundled\n  copy if an external library is found which is not of a new enough version.\n* Added neon_version_minimum() function call for run-time version detection.\n* neon_config.h has been removed.\n* Use closesocket() to close sockets on Win32 (Markus Fleck <fleck@isoc.de>).\n\nChanges in release 0.10.1:\n* Default expect-100 to OFF.\n\nChanges in release 0.10.0:\n* hip_xml API changes:\n - The search for a handler for a new child element begins at the\n   handler of the parent element, and carries on up the stack.\n   (previously, it always started from the base of the stack)\n - Documentation written: doc/parsing-xml.txt\n* Remove memory leaks and tidy debugging output in new properties code.\n* API changes to DAV locking interface: \n - New function: dav_lock_copy to copy a lock object.\n - Re-ordered arguments to callback of dav_lock_discover, and made the\n   lock object passed back const.\n - Fix leaks and crashes due to vague interface definitions.\n* API change to dav_propfind_set_complex: use a callback to return the\n  'private' structure.\n* NEON_NORMAL_BUILD and NEON_LIBTOOL_BUILD macros defined for setting\n  up neon's Makefile in a bundled build: see macros/neon.m4.\n* NEON_VPATH_BUNDLED macro added which takes separate srcdir and\n  builddir arguments for supporting VPATH builds (thanks to Peter Moulder \n  <pjm@bofh.asn.au>).\n* Added optional final argument to NEON_(VPATH_)BUNDLED, which gives\n  a set of actions to be run if the bundled build is chosen.\n* NEON_SSL checks for OpenSSL in /usr too.\n* API change: when using http_session_decide_proxy, it MUST be called\n  before using http_session_server to prevent the DNS lookup on the origin\n  server being optimised out.  The real scheme in use is passed to the \n  callback now.\n* New function, dav_207_ignore_unknown, to ignore any unknown XML fragments\n  in the 207 response.  Used by properties layer.\n\nChanges in release 0.9.2:\n* Fix using both dav_propfind_set_complex and dav_propfind_set_flat with the\n  same propfind_handler.\n\nChanges in release 0.9.1:\n* dav_propfind interface\n - Guarantee that the 'private' structure will be initialized to zero on\n   creation.\n - Make it the *callers* responsibility to free() the private structure.\n* Fix a few arguments/variables which mirrored globally declared symbols.\n\nChanges in release 0.9.0:\n* Removed old dav_propfind_* interface, replaced with a better, more\n  powerful, and easier to use interface:\n - 'dav_simple_propfind' interface for just fetching \"flat\" (byte-string)\n   properties.\n - 'dav_propfind_*' interface for fetching flat and/or \"complex\" (structured\n   XML) properties.\n - Lets you retrieve the 'status' information, to see what happened if\n   fetching the property failed (e.g 404 Not Found).\n* Fixes to doc/using-neon.txt (thanks to Greg Stein).\n* Allow building when srcdir != builddir (Mo DeJong <mdejong@cygnus.com>)\n\nChanges in release 0.8.1:\n* Fix segfault in PROPFIND code.\n\nChanges in release 0.8.0:\n* Fix for using COPY/MOVE over SSL (thanks to David Sloat).\n* Fix for using a proxy server and SSL.\n* Added 'http_get_scheme' API call.\n* Added 'http_redirect.h' to list of installed headers (thanks to everyone ;).\n* Changes for building on Windows (Peter Boos <PediB@colorfullife.com>)\n* Fixes for building on BeOS (Sam TH <sam@uchicago.edu> and David Reid\n  <dreid@jetnet.co.uk>).\n* Add buffering to socket code for pre-BONE BeOS systems (David Reid).\n* Interface changes for hip_xml:\n - Renamed hip_xml_add_(mixed_)handler to hip_xml_push_(mixed_)handler\n - Documentation updates.\n - Added HIP_ELM_UNUSED for lowest element id which should be used.\n*** MAJOR INTERFACE CHANGE ***\n - Removed 'http_status *' pointer from http_request_dispatch.\n - Added http_get_status(req) to retrieve the response-status information\n   instead. You don't have to declare an http_status object yourself now.\n* Similarly, added DAV_ELM_207_UNUSED for lowest element id which should\n  be used by users of dav_207_* code (incl. use of dav_propfind_*\n  code).\n* New NEON_* autoconf macro interface:\n - Use NEON_BUNDLED if sources are bundled, otherwise NEON_LIBRARY.\n - The NEON_XML_PARSER macro is NOT called automatically.  You must\n   call this yourself if using NEON_BUNDLED; see doc/using-neon.txt\n   for details.\n* Fix use of 'socket' in nsocket.h function prototypes (Greg Stein).\n* Remove extra backslash at line 69 of src/Makefile.incl (Dirk Bergstrom).\n* Examples directory is now a separate package.\n\nChanges in release 0.7.7:\n* Another fix for linking against a libtool-built expat (Greg Stein).\n\nChanges in release 0.7.6:\n* Better check for closed SSL connection after doing SSL_peek. (thanks\n  to Jeff Costlow <j.costlow@f5.com>).\n* Attempt at correct sock_block() implementation for SSL.\n* sock_peek() will return SOCK_CLOSED correctly.\n\nChanges in release 0.7.5:\n* Fixed workaround for linking against a libtool-built expat (Greg Stein).\n\nChanges in release 0.7.4:\n* Fix for fd leak on connect failure (David Sloat <d.sloat@f5.com>).\n* Fix for Digest auth against IIS5 (David Sloat).\n* Workaround for linking against a libtool-built libexpat.la (Greg Stein).\n\nChanges in release 0.7.3:\n* Check for -lsocket and -linet in configure.\n* Workaround for SSL problems.\n\nChanges in release 0.7.2:\n* Define SHELL in Makefile (thanks to Eric Mumpower <nocturne@arepa.com>).\n* Added 'all' target to Makefile (Greg Stein <gstein@lyra.org>)\n* Added '--with-expat' argument to configure (Greg Stein)\n* Added 'dav_propfind_destroy' function.\n\nChanges in release 0.7.1:\n* Don't register response body/header authentication callbacks if no \n  credentials-supplying callback has been registered (speed optimisation).\n\nChanges in release 0.7.0:\n* Deprecated use of 'NULL' to http_add_response_header_handler.\n  New interface, http_add_response_header_catcher, to register\n  a callback which is passed ALL response headers regardless of name.\n* Speed optimisation (~10%?): storing response-header handlers in a\n  hash table for faster look.\n* New SBUFFER_CAST() macro for getting to the 'char *' of an sbuffer\n  as fast as possible.\n\nChanges in release 0.6.1:\n* Fix for retrying request if connection is closed by server.\n* Make redirect hook work for >1 request per session.\n\nChanges in release 0.6.0:\n* New interface to allow following HTTP redirects (301/302 responses).\n  A callback must be given to get user confirmation if the request method\n  is not GET, HEAD, or PROPFIND.\n* New interface to determine whether the proxy server should be used\n  for a given request: http_session_decide_proxy.\n* Fix nget build again. Support automatic redirects in 'nget'.\n* Add --with-extra-includes and --with-extra-libs configure parameters\n  to point configure at \n\nChanges in release 0.5.1:\n* Prevent segfault if USE_DAV_LOCKS is defined, and a locking session\n  is not registered (thanks to David Sloat).\n\nChanges in release 0.5.0:\n* Rename xmalloc, xstrdup etc to ne_malloc, ne_strdup etc.\n* Some speed optimisation in response-header reading.\n* Use 'off_t' rather than 'size_t' in sock_progress callback,\n  sock_readfile_blocked, and sock_transfer.\n\nChanges in release 0.4.2:\n* Fix for sending request bodies after getting 100-continue response.\n\nChanges in release 0.4.1:\n* Fix nget build.\n\nChanges in release 0.4.0:\n* Install library headers into .../include/neon not .../include/libneon\n* Install all necessary library headers.\n* Compile support for WebDAV locking throughout the library\n* Rename md5.h to neon_md5.h (avoids conflict with md5.h in OpenSSL)\n* Rename socket.h to nsocket.h (avoids possible conflict with C library)\n* Update licensing notice on macros/neon*.m4: note that these files are\n  NOT under the LGPL, and can be used in other packages regardless of\n  the license the package uses.\n* Update NEON_LIBRARY m4 function to allow optional specification of\n  names of bundled neon/expat source directories.\n* Increase socket read timeout to 60 seconds.\n* Added an POST method: from Sander Alberink <sander.alberink@cmg.nl>.\n* Added 'http_get_request_headers' to return the sbuffer containing\n  all request headers.\n* Allow passing NULL as name to http_add_response_header_handler: \n  the handler callback is passed the entire header string, of ALL \n  response headers.\n\nChanges in release 0.3.1:\n* Compile fix for dav_locks.c (thanks to Paul D'Anna)\n\nChanges in release 0.3.0:\n* Rewrite of socket handling layer. All sock_* functions changed.\n* Added basic SSL support: --with-ssl (requires OpenSSL).\n  NOTE: Certificates are NOT presented for verification.\n* 'nget' accepts URL's using the 'https' scheme.\n* New example program, 'nserver', to display the Server: string, \n  e.g. 'nserver https://www.eu.c2.net/'\n* Fixed request re-send when persistent connection times out.\n* \"Hooks\" support: allow external hooks into the HTTP request/\n  response dispatch loop.\n* New printf-style interface for adding request headers.\n* Make symbols used in header files C++-safe (Tom Bednarz).\n* WebDAV locking support: lock discovery, LOCK (exclusive/shared)\n  UNLOCK. \"If:\" headers are sent as appropriate. Simple interface\n  for implementors of new methods to indicate which locks are \n  required for the method.\n* Primitive HTTP cookies support.\n* Primitive hack at a GNOME-based GUI example program \"nbrowse\".\n  Enable build with --enable-gnome-examples. It crashes, and\n  not much else. Requires GNOME and POSIX threads. Example usage:\n       'nbrowse dav.ics.uci.edu /msdav/'\n  Many thanks to Lee Mallabone for Gtk help, and showing how to\n  use Gtk and threads. \n\nChanges in release 0.2.0:\n* Use libtool: new configure options to select whether to build\n  shared and/or static libraries. Should build shared libraries\n  portably now.  \n* Complete rewrite of the hip_xml interface to use opaque pointers.\n  New functions: hip_xml_create, hip_xml_destroy: create parser.\n  hip_xml_{set,get}_error: Access to error string.\n  hip_xml_add_handler: Register callbacks for a set of elements.\n  hip_xml_valid: Returns whether the parse was valid or not.\n  Removed functions: hip_xml_init, hip_xml_finish.\n* Removed functions made reduntant by above changes in dav_207.\n* Don't include config.h in header files\n* Fix PROPFIND allprop request body (Michael Sobolev)\n* Added C++ safety macros around header files.\n* Added neon-config script for getting correct CFLAGS and LIBS\n  values for using libneon in applications.\n\nChanges in release 0.1.1:\n* Fix for short writes in GET\n\nChanges in release 0.1.0:\n* Initial release.\n"
  },
  {
    "path": "README.md",
    "content": "\n[![Build and test](https://github.com/notroj/neon/actions/workflows/ci.yml/badge.svg)](https://github.com/notroj/neon/actions/workflows/ci.yml)\n\n# neon\n\n_neon_ is an HTTP/1.1 and WebDAV client library, with a C language API.\n\nGitHub: https://github.com/notroj/neon | Web: https://notroj.github.io/neon/\n\nThe neon API and ABI are stable and maintain backwards compatibility\nsince 0.27 through to 1.0.0. From neon 1.0.0 onwards, semantic\nversioning will be used. https://semver.org/\n\nFeatures:\n\n - High-level interface to HTTP and WebDAV methods.\n - Low-level interface to HTTP request handling, to allow implementing\n   new methods easily.\n - Persistent connection support (HTTP/1.1 and HTTP/1.0 aware)\n - Basic and Digest authentication (RFC 7616/7617, including SHA-2, userhash)\n - Kerberos (Negotiate) and SSPI/NTLM authentication (Unix and Windows)\n - HTTP and SOCKS (v4/5) proxy support (including authentication)\n - SSL/TLS support using OpenSSL or GnuTLS (client certs via files or PKCS#11)\n - Generic WebDAV 207 XML response handling mechanism\n - XML parsing using expat or libxml2\n - Easy generation of error messages from 207 error responses\n - Basic HTTP/1.1 methods: GET, PUT, HEAD, OPTIONS, conditional PUT\n - WebDAV resource manipulation: MOVE, COPY, DELETE, MKCOL.\n - WebDAV metadata support: set and remove properties (PROPPATCH), query\n   any set of properties (PROPFIND).\n - WebDAV locking and ACL (RFC 3744) support\n - Autoconf macros supplied for easily embedding neon directly inside \n   an application source tree.\n\nProvides lower-level interfaces to directly implement new HTTP\nmethods, and higher-level interfaces so that you don't have to worry\nabout the lower-level stuff.\n\nThe neon library source code is licensed under the GNU Library GPL;\nsee src/COPYING.LIB for full details.  The manual and test suite are\nlicensed under the terms of the GNU GPL; see test/COPYING for terms.\nThe autoconf macros in the \"macros\" directory are under a less\nrestrictive license, see each file for details.\n\n## Building neon\n\nGrab the latest neon release tarball from https://notroj.github.io/neon/ and build \nas follows:\n\n```bash\n./configure --with-ssl=openssl --prefix=/path/to/install\nmake\nmake check\n```\n\nThird-party libraries are required for certain features:\n\n- _expat_ or _libxml2_ for XML parsing and WebDAV support (https://github.com/libexpat/libexpat or https://github.com/gnome/libxml2)\n- _OpenSSL_ or _GnuTLS_ for SSL/TLS support (https://openssl-library.org/ or https://gnutls.org/)\n- _Libntlm_ for NTLM authentication support (https://gitlab.com/gsasl/libntlm)\n- _GSSAPI_ libraries from a Kerberos distribution for Negotiate authentication\n- _zlib_ for compressed response support (https://github.com/madler/zlib)\n- _libproxy_ for system proxy support (see https://github.com/libproxy/libproxy)\n\n~~~\nneon is Copyright (C) 1999-2026 Joe Orton\nPortions are:\nCopyright (C) Aleix Conchillo Flaque\nCopyright (C) Arfrever Frehtes Taifersar Arahesis\nCopyright (C) Arun Garg\nCopyright (C) Free Software Foundation, Inc.\nCopyright (C) Henrik Holst\nCopyright (C) Jiang Lei\nCopyright (C) Karl Ove Hufthammer.\nCopyright (C) Michael Sobolev\nCopyright (C) Nobuyuki Tsuchimura\nCopyright (C) Sylvain Glaize\nCopyright (C) Temuri Doghonadze\nCopyright (C) Thomas Schultz\nCopyright (C) Vladimir Berezniker\nCopyright (C) Yves Martin\n~~~\n"
  },
  {
    "path": "THANKS",
    "content": "Thanks go to the following people for contributing to neon development\nwith code, patches, or good bug reports or suggestions.\n\nArun Garg, Blair Zajac, Branko Èibej, Daniel Berlin, David Sloat,\nDavid Reid, Dirk Bergstrom, Ulrich Drepper, Gerald Richter, Greg\nStein, Gregor Bornemann, Jeff Johnson, Jeremy Elson, Jim Whitehead,\nJohan Lindh, Justin Erenkrantz, Kai Sommerfeld, Keith Wannamaker, Lee\nMallabone, Magnus Sirwiö, Markus Mueller, Max Bowsher, Michael\nSobolev, Mike Rosellini, Mo DeJong, Noriaki Takamiya, Olof Oberg,\nPawel Golaszewski, Peter Boos, Peter Moulder, rado, Risko Gergely,\nRodney Dawes, Sam TH, Sander Alberink, Sander Striker, Stefan Esser,\nShane Mayer, Taisuke Yamada, Teng Xu, Tom Bednarz, Tom Lee, Tommi\nKomulainen, Torsten Kalix, Wilfredo Sánchez, Daniel Veillard, Vladimir\nBerezniker, Jiang Lei, Werner Baumann, Mike DiCuccio, Gisle Vanem,\nHans Meine, Laszlo Boszormenyi, Matthias Miller, Albert Chin, \nKiyo Kelvin Lee, D.J. Heap, Dongsheng Song, Aleix Conchillo Flaque.\n"
  },
  {
    "path": "TODO",
    "content": "\nTo Do List for neon                                      -*- text -*-\n===================\n\nPlease submit feature requests to <neon@lists.manyfish.co.uk>\n\nFor one-point-oh\n----------------\n\nLonger term\n-----------\n\n6. PUT with ranges... ne_put_range\n\n9. DeltaV support (http://www.webdav.org/deltav/). See also the\n   subversion project (http://subversion.tigris.org/) who might build\n   a versioning system over DAV.\n\n14. Improved request-header manipulation... some kind of indexed table\n    (a la Apache, libghttp, so we're sure we don't add the same header\n    to the request twice.  Better control over adding Cache-Control\n    headers would be good too.\n\n21. Storing multiple authentication \"sessions\" within an actual\n    auth_session, so I can log into e.g. /foo/ and /bar/ (which are\n    not in the same authentication domain) and switch between them\n    without having to re-enter passwords all the time.\n\n46. Asynchronous request-dispatching? Makes integration into GUI loop\n    easy... any other reasons?  Must leave existing request_dispatch\n    interface intact.\n\n50. opendir/readdir/closedir-esque interface for PROPFIND depth 1, \n    a la EZDAV. (cadaver has it already)\n\n"
  },
  {
    "path": "autogen.sh",
    "content": "#!/bin/sh\nrm -f ltconfig ltmain.sh config.cache aclocal.m4 config.guess config.sub\n# remove the autoconf cache\nrm -rf autom4te*.cache\n# create a .version file for configure.in\nif test ! -f .version; then\n   # Building from SVN rather than in a release\n   echo 0.0.0-dev > .version\n   # for the documentation:\n   date +\"%e %B %Y\" | tr -d '\\n' > doc/date.xml\n   echo 0.0.0-dev > doc/version.xml\nfi\nset -e\nprintf  \"libtoolize... \"\n: \"${LIBTOOLIZE:=\"$(command -v libtoolize || command -v glibtoolize)\"}\"\nif ${LIBTOOLIZE} --help | grep -- --install > /dev/null; then\n   ${LIBTOOLIZE} --copy --force --install >/dev/null;\nelse\n   ${LIBTOOLIZE} --copy --force >/dev/null\nfi\nprintf  \"aclocal... \"\n${ACLOCAL:-aclocal} -I macros\nprintf  \"autoheader... \"\n${AUTOHEADER:-autoheader} -Wall\nprintf  \"autoconf... \"\n${AUTOCONF:-autoconf} -Wall -Werror\necho okay.\n# remove the autoconf cache\nrm -rf autom4te*.cache\n"
  },
  {
    "path": "config.hw.in",
    "content": "/*                                                      -*- c -*-\n   Win32 config.h\n   Copyright (C) 1999-2000, Peter Boos <pedib@colorfullife.com>\n   Copyright (C) 2002-2006, Joe Orton <joe@manyfish.co.uk>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n   \n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n#if defined(_WIN32) && !defined(WIN32)\n#define WIN32\n#endif\n\n#ifdef WIN32\n\n#define NEON_VERSION \"@VERSION@\"\n#define NE_VERSION_MAJOR (@MAJOR@)\n#define NE_VERSION_MINOR (@MINOR@)\n\n#define HAVE_ERRNO_H\n#define HAVE_LIMITS_H\n#define HAVE_STDLIB_H\n#define HAVE_STRING_H\n\n#define HAVE_MEMCPY\n#define HAVE_SETSOCKOPT\n\n#define HAVE_SSPI\n\n#define NE_HAVE_TS_SSL 1\n\n/* Define to enable debugging */\n#define NE_DEBUGGING 1\n\n#ifdef _WIN64\n#define NE_FMT_SIZE_T \"I64u\"\n#define NE_FMT_SSIZE_T \"I64d\"\n#else\n#define NE_FMT_SIZE_T \"u\"\n#define NE_FMT_SSIZE_T \"d\"\n#endif\n#define NE_FMT_OFF_T \"ld\"\n#define NE_FMT_OFF64_T \"I64d\"\n#define NE_FMT_NE_OFF_T NE_FMT_OFF_T\n#define NE_FMT_TIME_T \"ld\"\n\n#ifndef NE_FMT_XML_SIZE\n#define NE_FMT_XML_SIZE \"d\"\n#endif\n\n#define SIZEOF_INT 4\n#define SIZEOF_LONG 4\n\n/* Win32 uses a underscore, so we use a macro to eliminate that. */\n/* VS2015 has this already defined */\n#if (_MSC_VER < 1900)\n#define snprintf\t\t\t_snprintf\n#endif\n/* VS2008 has this already defined */\n#if (_MSC_VER < 1500)\n#define vsnprintf\t\t\t_vsnprintf\n#endif\n\n#if defined(_MSC_VER) && _MSC_VER >= 1400\n#define strcasecmp\t\t\t_strcmpi\n#define strncasecmp\t\t\t_strnicmp\n#else\n#define strcasecmp\t\t\tstrcmpi\n#define strncasecmp\t\t\tstrnicmp\n#endif\n#if defined(_MSC_VER) && _MSC_VER >= 1300\n#define HAVE_STRTOLL\n/* VS2013 has this already defined */\n#if _MSC_VER < 1800\n#define strtoll\t\t\t\t_strtoi64\n#endif\n#endif\n#ifdef _WIN64\n#define ssize_t\t\t\t\t__int64\n#else\n#define ssize_t\t\t\t\tint\n#endif\n/* VS2015 has this already defined */\n#if defined (_MSC_VER) && (_MSC_VER < 1900)\n#define inline                          __inline\n#endif\n#if defined(NE_LFS)\n#define lseek64\t\t\t\t_lseeki64\n#define fstat64\t\t\t\t_fstat64\n#define stat64\t\t\t\t__stat64\n#else\n#define off_t                           _off_t\n#endif\n\n#ifndef USE_GETADDRINFO\n#define in_addr_t                       unsigned int\ntypedef int socklen_t;\n#endif\n\n#include <io.h>\n\n#endif\n"
  },
  {
    "path": "configure.ac",
    "content": "AC_PREREQ(2.58) dnl 2.58 required for AS_HELP_STRING\n\ndnl Extract the version (sans LF) from .version, created at release-time.\nm4_define(ne_version, [m4_translit(m4_include(.version), [\n])])\n\nAC_INIT(neon, ne_version,,,[https://notroj.github.io/neon/])\n\nAC_COPYRIGHT([Copyright 2000-2022 Joe Orton and others\nThis configure script may be copied, distributed and modified under the \nterms of the GNU Library General Public license; see src/COPYING.LIB for\nmore details.])\n\nAC_CONFIG_MACRO_DIR([macros])\nAC_CONFIG_HEADERS([config.h])\nAC_CONFIG_SRCDIR(src/ne_request.c)\n\nNEON_WITH_LIBS\n\n# Pass through initial LDFLAGS verbatim to neon-config, so that extra\n# libraries which are detected (e.g. OpenSSL) can still be found when\n# building using the --libs output of neon-config.\nuser_LDFLAGS=$LDFLAGS\n\n# By default, allow 'make install' to work.\nALLOW_INSTALL=yes\n\nAC_DEFINE([_GNU_SOURCE], 1, [Always defined to enable GNU extensions])\nAC_DEFINE([NEON_IS_LIBRARY], 1, [Defined when neon is built as a library])\n\nAH_BOTTOM([\n/* Enable leak-tracking versions of ne_*alloc when NEON_MEMLEAK is enabled */\n#ifdef NEON_MEMLEAK\n# include \"memleak.h\"\n#endif])\n\nAC_PROG_INSTALL\n\nAC_ARG_ENABLE(webdav, \n  AS_HELP_STRING([--disable-webdav],[disable WebDAV support]))\n\nif test \"$enable_webdav\" = \"no\"; then\n  NEON_WITHOUT_WEBDAV\nelse\n  # Yes, we do need an XML parser. The _BUNDLED macros handle\n  # this normally.\n  NEON_NEED_XML_PARSER=yes\nfi\n\n# The bundled macros also set this, which makes sure we recurse\n# into the 'src' directory.\nNEON_BUILD_BUNDLED=yes\n\n# Define NEON_VERSION etc and make the appropriate substitutions.\nNE_VERSIONS_BUNDLED\n\nLIBNEON_SOURCE_CHECKS\n\ndnl Avoid libtool 1.5 bug where configure fails if a C++ compiler\ndnl is not available.\nm4_ifdef([AC_LIBTOOL_TAGS], [AC_LIBTOOL_TAGS([])])\n\nAC_DISABLE_SHARED\nm4_ifdef([LT_INIT], [LT_INIT(pic-only)], [AC_PROG_LIBTOOL])\n\nAC_EXEEXT\n\n# Checks to compile test suite\nNEON_TEST\n\n# Use the libtool-type build.\nNEON_LIBTOOL_BUILD\n# Find an XML parser\nNEON_XML_PARSER\n# Internationalization support.\nNEON_I18N()\n\n# Extra checks for debugging, compiler warnings\nNEON_DEBUG\n# Leave till last to prevent CFLAGS affecting checks.\nNEON_WARNINGS\n\nCPPFLAGS=\"$CPPFLAGS -I\\${top_builddir}\"\n\nAC_ARG_ENABLE(memleak, \n  AS_HELP_STRING([--enable-memleak],\n                 [for test builds only: enable memory leak checking]))\n\nif test \"$enable_memleak\" = \"yes\"; then\n  CPPFLAGS=\"$CPPFLAGS -DNEON_MEMLEAK -I\\$(top_srcdir)/src\"\n  # disable 'make install'\n  ALLOW_INSTALL=memleak\nfi\n\nAC_ARG_ENABLE(auto-libproxy, \n  AS_HELP_STRING([--enable-auto-libproxy],\n                 [for using libproxy during session creation]))\n\nif test \"$enable_auto_libproxy\" = \"yes\"; then\n  AC_DEFINE(NE_ENABLE_AUTO_LIBPROXY, 1, [to use libproxy automatically])\nfi\n\n# Enable tests for optional features\nTESTS=\"\\$(BASIC_TESTS)\"\nHELPERS=\"\"\nif test $NE_FLAG_SSL = yes; then\n   # Only enable SSL tests if an openssl binary is found (needed to make\n   # certs etc).\n   AC_PATH_PROG(OPENSSL, openssl, notfound)\n   if test \"$OPENSSL\" != \"notfound\"; then\n     TESTS=\"$TESTS \\$(SSL_TESTS)\"\n     HELPERS=\"$HELPERS \\$(SSL_HELPERS)\"\n   else\n     AC_MSG_WARN([no openssl binary in \\$PATH: SSL tests disabled])\n   fi\n\n   AC_PATH_PROG(CERTUTIL, certutil, notfound)\n   AC_PATH_PROG(PK12UTIL, pk12util, notfound)\nfi\nif test $NE_FLAG_ZLIB = yes; then\n   TESTS=\"$TESTS \\$(ZLIB_TESTS)\"\n   HELPERS=\"$HELPERS \\$(ZLIB_HELPERS)\"\nfi\nif test x$enable_webdav != xno; then\n   TESTS=\"$TESTS \\$(DAV_TESTS)\"\nfi\n\nAC_ARG_ENABLE(tests-install,\n  AS_HELP_STRING([--enable-tests-install],\n                 [enable installation of the test suite]),,\n  [enable_tests_install=no])\n\n# If test suite installation is not required, it's more\n# efficient to link the test programs using -no-install:\nif test \"$enable_tests_install\" = \"no\"; then\n  TEST_LDFLAGS=\"-no-install\"\nfi\n\nAC_SUBST(TEST_LDFLAGS)\n\nAC_PATH_PROG(PKG_CONFIG, pkg-config, no)\nif test \"$PKG_CONFIG\" != \"no\"; then\n   # pkg-config >= 0.18 will use \"Libs.private\" iff necessary,\n   # older versions which don't recognize that field may always\n   # need all libraries in Libs.\n   if $PKG_CONFIG --atleast-pkgconfig-version=0.18; then :; else\n      NEON_PC_LIBS=${NEON_LIBS}\n   fi\nfi\nAC_SUBST(NEON_PC_LIBS)\n\n# Pass the interface version on to libtool when linking libneon.la\nNEON_LINK_FLAGS=\"-version-info ${NE_LIBTOOL_VERSINFO}\"\n# If any non-default ABI variations are used, add them to the SONAME:\n### disabled for backwards-compat with 0.27.x\n#if test \"x${NE_LIBTOOL_RELEASE}y\" != \"xy\"; then\n#   NEON_LINK_FLAGS=\"${NEON_LINK_FLAGS} -release ${NE_LIBTOOL_RELEASE}\"\n#fi\n\ngl_LD_VERSION_SCRIPT\n# If ld version scripts are supported, enable symbol versioning.\n# Otherwise, fall back to any libtool-supported symbol export\n# restrictions; ne__* symbols are not exported.\nif test \"x$have_ld_version_script\" = \"xyes\"; then\n  NEON_LINK_FLAGS=\"$NEON_LINK_FLAGS -Wl,--version-script=\\$(top_srcdir)/src/neon.vers\"\nelse\n  NEON_LINK_FLAGS=\"$NEON_LINK_FLAGS -export-symbols-regex '^ne_[[^_]]'\"\nfi \n\nif test x${enable_shared} = xno; then\n   # Defining NE_PRIVATE as the empty string would work; using a\n   # non-empty but redundant string 'extern' avoids any possible cpp\n   # confusion with from an empty macro.\n   CPPFLAGS=\"$CPPFLAGS -DNE_PRIVATE=extern\"\n   AC_MSG_NOTICE([Private symbol suppression disabled for static library build])\nfi\n\n# Bundled language catalogs\nALL_LINGUAS=\"cs de fr ja ka nn pl ru tr zh_CN\"\nAC_SUBST(ALL_LINGUAS)\n\nAC_CONFIG_FILES([neon-config], [chmod +x neon-config])\nAC_CONFIG_FILES([Makefile src/Makefile test/Makefile neon.pc])\nAC_CONFIG_FILES([test/makekeys:test/makekeys.sh], [chmod +x test/makekeys])\n\nAC_SUBST(NEON_VERSION)\nAC_SUBST(NEON_BUILD_BUNDLED)\nAC_SUBST(top_builddir)\nAC_SUBST(user_LDFLAGS)\nAC_SUBST(HELPERS)\nAC_SUBST(TESTS)\nAC_SUBST(ALLOW_INSTALL)\n\nAC_OUTPUT\n\n# for VPATH builds:\ntest -d test/common || mkdir test/common\n\nAC_MSG_NOTICE([Configured to build AC_PACKAGE_STRING:\n\n  Install prefix:   ${prefix}\n  Compiler:         ${CC}\n  XML Parser:       ${neon_xml_parser_message}\n  SSL library:      ${ne_SSL_message}\n  zlib support:     ${ne_ZLIB_message}\n  GSSAPI support:   ${ne_GSSAPI_message}\n  NTLM support:     ${ne_NTLM_message}\n  libproxy support: ${ne_LIBPXY_message}\n\n  Building:         Shared=${enable_shared}, Static=${enable_static}, Libtool Version=${NE_LIBTOOL_VERSINFO}\n])\n\ncase $ALLOW_INSTALL in\nmemleak)\n  AC_MSG_NOTICE([Configured with development-only flags:\n\nWARNING: This copy of neon has been configured with memory leak checking\nWARNING: enabled, which should only be used in a development build of neon.\nWARNING: This neon library should not be installed for use by applications.\n]);;\nesac\n"
  },
  {
    "path": "doc/biblio.xml",
    "content": "<bibliography id=\"biblio\"> <!-- -*- xml -*- -->\n\n<biblioentry id=\"bib.ssltls\">\n  <abbrev>SSL-and-TLS</abbrev>\n  <title><ulink url=\"http://www.rtfm.com/sslbook/\">SSL and\n  TLS: Designing and Building Secure Systems</ulink></title>\n  <author><firstname>Eric</firstname><surname>Rescorla</surname></author>\n  <isbn>0-201-62598-3</isbn>\n  <publisher><publishername>Addison-Wesley</publishername></publisher>\n  <pubdate>March 2001</pubdate>\n</biblioentry>\n\n<biblioentry id=\"bib.xmlnames\">\n  <abbrev>REC-XML-names</abbrev>\n  <corpauthor>World Wide Web Consortium</corpauthor>\n  <title><ulink url=\"http://www.w3.org/TR/REC-xml-names\">Namespaces in XML</ulink></title>\n  <pubdate>January 1999</pubdate>\n</biblioentry>\n\n<biblioentry id=\"bib.rfc2616\">\n  <abbrev>RFC2616</abbrev>\n  <title><ulink url=\"http://www.ietf.org/rfc/rfc2616.txt\">Hypertext Transfer \n  Protocol&mdash;HTTP/1.1</ulink></title>\n  <authorgroup>\n    <author><firstname>Roy</firstname><surname>Fielding</surname></author>\n    <author><firstname>Jim</firstname><surname>Gettys</surname></author>\n    <author><firstname>Jeff</firstname><surname>Mogul</surname></author>\n    <author><firstname>Henrik</firstname><surname>Frystyk</surname></author>\n    <author><firstname>Larry</firstname><surname>Masinter</surname></author>\n    <author><firstname>Paul</firstname><surname>Leach</surname></author>\n    <author><firstname>Tim</firstname><surname>Berners-Lee</surname></author>\n  </authorgroup>\n  <publishername>IETF</publishername>\n  <pubdate>June 1999</pubdate>\n</biblioentry>\n\n<biblioentry id=\"bib.rfc2518\">\n  <abbrev>RFC2518</abbrev>\n  <title><ulink url=\"http://www.ietf.org/rfc/rfc2518.txt\">HTTP Extensions for Distributed Authoring&mdash;WEBDAV</ulink></title>\n  <authorgroup>\n    <author><firstname>Yaron</firstname><surname>Goland</surname></author>\n    <author><firstname>Jim</firstname><surname>Whitehead</surname></author>\n    <author><firstname>Asad</firstname><surname>Faizi</surname></author>\n    <author><firstname>Steve</firstname><surname>Carter</surname></author>\n    <author><firstname>Del</firstname><surname>Jensen</surname></author>\n  </authorgroup>\n  <publishername>IETF</publishername>\n  <pubdate>February 1999</pubdate>\n</biblioentry>\n\n<biblioentry id=\"bib.rfc3280\">\n  <abbrev>RFC3280</abbrev>\n  <title><ulink url=\"http://www.ietf.org/rfc/rfc3280.txt\">Internet X.509 Public Key Infrastructure\n       Certificate and Certificate Revocation List (CRL) Profile</ulink></title>\n  <authorgroup>\n    <author><firstname>Russel</firstname><surname>Housley</surname></author>\n    <author><firstname>Warwick</firstname><surname>Ford</surname></author>\n    <author><firstname>Tim</firstname><surname>Polk</surname></author>\n    <author><firstname>David</firstname><surname>Solo</surname></author>\n  </authorgroup>\n  <publishername>IETF</publishername>\n  <pubdate>April 2002</pubdate>\n</biblioentry>\n\n<!-- RFCs: 2617 -->\n\n<!-- Other interesting RFCs:\n\n 3490 : Internationalizing Domain Names in Applications (IDNA) \n 3493 : Basic Socket Interface Extensions for IPv6 \n -->\n\n</bibliography>\n"
  },
  {
    "path": "doc/feat.xml",
    "content": "    <sect1 id=\"features\">\n      <title>Feature list</title>\n\n      <para>The major features of the neon library are as follows:</para>\n\n      <itemizedlist>\n\n\t<listitem><para>A high-level interface to common HTTP and WebDAV\nmethods.  This allows you to easily dispatch a GET or a MKCOL request\nagainst a resource with a single function call.</para></listitem>\n\n\t<listitem><para>A low-level interface for HTTP request\nhandling; allowing you to implement requests using arbitrary methods\nand request headers, capture arbitrary response headers, and so\non.</para></listitem>\n\n\t<listitem><para>Persistent connection support; neon groups a\nset of requests to a server into a \"session\"; requests within that\nsession can use a persistent (also known as \"keep-alive\")\nconnection.</para></listitem>\n\n\t<listitem><para>Modern HTTP authentication support: a complete\nimplementation of the new authentication standard, RFC2617, supporting\nthe Digest, Basic, and Negotiate protocols.  Credentials are supplied\nby an application-defined callback as appropriate.</para></listitem>\n\n\t<listitem><para>Proxy server support; a session can be set to\nuse a proxy server.  Authentication is supported for the Proxy as well\nas the origin server.  The system's proxy configuration can be\noptionally used, on some platforms.</para></listitem>\n\n\t<listitem><para>Complete SSL support; a simple interface for\nenabling SSL, hiding the complexity of using an SSL library directly.\nClient certificate support, callback-based server certificate\nverification, along with functions to load trusted CA certificates.\nSmartcard-based client certs are also supported via a wrapper\ninterface for PKCS#11 modules.</para></listitem>\n\n\t<listitem><para>Compressed response support: responses\n\tcompressed using the \"deflate\" algorithm can be transparently\n\tdecompressed.</para></listitem>\n\n\t<listitem><para>Generic XML parsing interface for handling XML\nresponse bodies using SAX-like callbacks.  Both the expat and libxml\nXML parser libraries are supported.</para></listitem>\n\n\t<listitem><para>WebDAV metadata support; set and remove\nproperties, query properties (PROPFIND); simple interface for\nretrieving \"flat\" byte-string properties, more advanced support for\nparsing \"complex\" structured XML properties.</para></listitem>\n\n<!--\n\t<listitem><para>WebDAV locking support</para></listitem>\n-->\n\n\t<listitem><para>Build environment support: the neon source\ntree is designed so that it can be embedded in your application's\nbuild tree; autoconf macros are supplied for integration.  To get\nstarted quickly a <xref linkend=\"refconfig\"/> script is included,\nto easily determine how to compile and link against an installed copy\nof neon</para></listitem>\n\n\t<listitem><para>Complete test suite: the neon test suite\ncomprises half as many lines of source code as the library itself,\nincluding many tests for protocol compliance in network behaviour, and\nthat the library implementation meets the guarantees made by the\nAPI.</para> </listitem>\n\n<!-- \n\n\t<listitem><para>Thorough documentation: neon documentation is\nprovided in HTML and man page formats (from a single DocBook XML\nsource)</para></listitem>\n\n-->\n\n      </itemizedlist>\n\t\n    </sect1>\n"
  },
  {
    "path": "doc/html.xsl",
    "content": "<?xml version='1.0'?>\n\n<!-- This file wraps around the DocBook HTML XSL stylesheet to customise\n   - some parameters; add the CSS stylesheet, etc.\n -->\n\n<xsl:stylesheet xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\"\n                version='1.0'\n                xmlns=\"http://www.w3.org/TR/xhtml1/transitional\"\n                exclude-result-prefixes=\"#default\">\n\n<xsl:import href=\"http://docbook.sourceforge.net/release/xsl/current/html/chunk.xsl\"/>\n\n<xsl:variable name=\"html.stylesheet\">manual.css</xsl:variable>\n\n<!-- for sections with id attributes, use the id in the filename.\n  This produces meaningful (and persistent) URLs for the sections. -->\n<xsl:variable name=\"use.id.as.filename\" select=\"1\"/>\n\n<!-- enable the shaded verbatim (programlisting etc) blocks. -->\n<!-- <xsl:variable name=\"shade.verbatim\" select=\"1\"/> -->\n\n<!-- add class=\"programlisting\" attribute on the <pre>s from\n  <programlisting>s so that the CSS can style them nicely. -->\n<xsl:attribute-set name=\"shade.verbatim.style\">\n  <xsl:attribute name=\"class\">programlisting</xsl:attribute>\n</xsl:attribute-set>\n\n<!-- use sane ANSI C function prototypes -->\n<xsl:variable name=\"funcsynopsis.style\" select=\"'ansi-table'\"/>\n\n<!-- split each sect1 into a separate chunk -->\n<xsl:variable name=\"chunk.first.sections\" select=\"1\"/>\n\n<!-- don't generate table of contents within each chapter chunk. -->\n<xsl:variable name=\"generate.chapter.toc\" select=\"0\"/>\n\n<xsl:variable name=\"generate.appendix.toc\" select=\"0\"/>\n\n<!-- don't include manual page numbers in refentry cross-references, they\n  look weird -->\n<xsl:variable name=\"refentry.xref.manvolnum\" select=\"0\"/>\n\n<!-- do generate variablelist's as tables -->\n<xsl:variable name=\"variablelist.as.table\" select=\"1\"/>\n\n<!-- and css'ize the tables so they can look pretty -->\n<xsl:variable name=\"table.borders.with.css\" select=\"1\"/>\n\n<!-- disable ugly tabular output -->\n<xsl:variable name=\"funcsynopsis.tabular.threshold\" select=\"99999\"/>\n\n<!-- change some presentation choices --> \n<xsl:template match=\"type\">\n  <xsl:call-template name=\"inline.italicseq\"/>\n</xsl:template>\n\n<xsl:template match=\"parameter\">\n  <xsl:call-template name=\"inline.monoseq\"/>\n</xsl:template>\n\n<!-- enclose the whole funcprototype in <code> -->\n<xsl:template match=\"funcprototype\" mode=\"ansi-nontabular\">\n  <div class=\"funcprototype\"><code>\n     <xsl:apply-templates mode=\"ansi-nontabular\"/>\n  </code></div>\n</xsl:template>\n\n</xsl:stylesheet>\n\n"
  },
  {
    "path": "doc/man.xsl",
    "content": "<?xml version='1.0'?>\n\n<!-- This file wraps around the DocBook XSL manpages stylesheet to customise\n   - some parameters; add the CSS stylesheet, etc.\n -->\n\n<xsl:stylesheet xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\"\n                version='1.0'\n                xmlns=\"http://www.w3.org/TR/xhtml1/transitional\"\n                exclude-result-prefixes=\"#default\">\n\n<xsl:import href=\"http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl\"/>\n\n<xsl:param name=\"man.output.quietly\" select=\"1\"/>\n\n<xsl:param name=\"man.endnotes.list.enabled\">1</xsl:param>\n\n<xsl:param name=\"man.endnotes.are.numbered\">1</xsl:param>\n\n<!-- by convention, only RFC references will be used. -->\n<xsl:param name=\"man.endnotes.list.heading\">References</xsl:param>\n\n<xsl:param name=\"man.authors.section.enabled\">0</xsl:param>\n\n<xsl:template match=\"xref\">\n  <xsl:variable name=\"target\" select=\"id(@linkend)\"/>\n  <xsl:choose>\n    <!-- Target is a refname element inside a refentry -->\n    <xsl:when test=\"$target/self::refname\">\n      <xsl:variable name=\"refentry\" select=\"$target/ancestor::refentry\"/>\n      <xsl:variable name=\"manvolnum\">\n        <xsl:choose>\n          <xsl:when test=\"$refentry/refmeta/manvolnum\">\n            <xsl:value-of select=\"$refentry/refmeta/manvolnum\"/>\n          </xsl:when>\n          <xsl:otherwise>3</xsl:otherwise>\n        </xsl:choose>\n      </xsl:variable>\n      <xsl:text>\\fB</xsl:text>\n      <xsl:value-of select=\"$target\"/>\n      <xsl:text>\\fR(</xsl:text>\n      <xsl:value-of select=\"$manvolnum\"/>\n      <xsl:text>)</xsl:text>\n    </xsl:when>\n    <xsl:otherwise>\n      <xsl:apply-imports/>\n    </xsl:otherwise>\n  </xsl:choose>\n</xsl:template>\n\n</xsl:stylesheet>\n"
  },
  {
    "path": "doc/manual.css",
    "content": "\np, pre.funcsynopsisinfo { margin-left: 0.4em; margin-right: 0.4em; }\n\nspan.term { margin-left: 0.6em; margin-bottom: 0.0em }\n\ndiv.legalnotice { font-size: 80%; margin-left: 2em; }\n\na:visited { color: darkgreen; }\n\ndiv.navheader { border-top: 1px solid #bbf2bb; }\ndiv.navfooter { border-bottom: 1px solid #bbf2bb; }\n\ndiv.funcprototype { margin-top: 0.2em; margin-left: 0.4em; margin-bottom: 0.2em; }\n\npre.programlisting, pre.screen { \n\tbackground-color: #dddddd;\n\tmargin-left: 0.6em; margin-right: 1em;\n\tpadding: 0.3em; width: 50em;\n}\n\ndiv.funcsynopsis, div.cmdsynopsis { \n\tbackground-color: #dddddd;\n\tmargin-left: 0.4em; margin-right: 0.4em;\n\tpadding: 0.1em;\n}\n\ndiv.warning {\n        border: 1px solid #777777;\n}\n\nh1.title { border-bottom: thick solid #bbf2bb; padding-bottom: 0.1em; }\n\ndiv.toc { \n\tborder-left: thick solid #bbf2bb; padding-left: 0.5em;\n\t}\n\nh2, h3 { padding-left: 0.2em; padding-top: -0.1em; }\n\nh2 { background-color: #bbf2bb; font-size: 110%; \n     padding-bottom: 0.3em; padding-top: 0.2em; spacing-top: 0.1em; }\n\nh3 { border-bottom: 1px solid #bbf2bb; }\n"
  },
  {
    "path": "doc/manual.xml",
    "content": "<?xml version='1.0'?> <!-- -*- nxml -*- -->\n\n<!DOCTYPE book PUBLIC \"-//OASIS//DTD DocBook XML V4.5//EN\"\n  \"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd\" [\n\n<!ENTITY % isoent SYSTEM\n    \"http://www.oasis-open.org/docbook/xml/4.5/ent/isonum.ent\">\n<!ENTITY % isopub SYSTEM\n    \"http://www.oasis-open.org/docbook/xml/4.5/ent/isopub.ent\">\n\n%isoent;\n%isopub;\n\n<!-- date/version stamp files created as release tarball is rolled -->\n<!ENTITY date SYSTEM \"date.xml\">\n<!ENTITY version SYSTEM \"version.xml\">\n<!ENTITY copyright \"<copyright><year>2001-2026</year><holder>Joe Orton</holder></copyright>\">\n\n<!ENTITY neon \"neon\">\n\n<!-- a useful entity for writing reference examples -->\n<!ENTITY egsess \"ne_session *sess = ne_session_create(...);\">\n\n<!ENTITY null \"<literal>NULL</literal>\">\n\n<!ENTITY nul \"<literal>NUL</literal>\">\n\n<!-- xml.xml entities: -->\n<!ENTITY startelm \"<emphasis>start-element</emphasis>\">\n<!ENTITY cdata \"<emphasis>character-data</emphasis>\">\n<!ENTITY endelm \"<emphasis>end-element</emphasis>\">\n\n<!ENTITY section.features SYSTEM \"feat.xml\">\n<!ENTITY section.using SYSTEM \"using.xml\">\n<!ENTITY section.xml SYSTEM \"xml.xml\">\n<!ENTITY section.security SYSTEM \"security.xml\">\n<!ENTITY section.ssl SYSTEM \"ssl.xml\">\n\n<!ENTITY biblio SYSTEM \"biblio.xml\">\n\n<!ENTITY refneon SYSTEM \"ref/neon.xml\">\n<!ENTITY refconfig SYSTEM \"ref/config.xml\">\n\n<!ENTITY refsess SYSTEM \"ref/sess.xml\">\n<!ENTITY refsessflags SYSTEM \"ref/sessflags.xml\">\n<!ENTITY referr SYSTEM \"ref/err.xml\">\n<!ENTITY refopts SYSTEM \"ref/opts.xml\">\n<!ENTITY refproxy SYSTEM \"ref/proxy.xml\">\n<!ENTITY refsslvfy SYSTEM \"ref/sslvfy.xml\">\n<!ENTITY refsslvers SYSTEM \"ref/sslvers.xml\">\n<!ENTITY refsslproto SYSTEM \"ref/sslproto.xml\">\n<!ENTITY refsslcert SYSTEM \"ref/sslcert.xml\">\n<!ENTITY refsslcert2 SYSTEM \"ref/sslcert2.xml\">\n<!ENTITY refsslcertio SYSTEM \"ref/sslcertio.xml\">\n<!ENTITY refssldname SYSTEM \"ref/ssldname.xml\">\n<!ENTITY refssltrust SYSTEM \"ref/ssltrust.xml\">\n<!ENTITY refsslctx SYSTEM \"ref/sslctx.xml\">\n<!ENTITY refreq SYSTEM \"ref/req.xml\">\n<!ENTITY refreqhdr SYSTEM \"ref/reqhdr.xml\">\n<!ENTITY refresphdr SYSTEM \"ref/resphdr.xml\">\n<!ENTITY refrespbody SYSTEM \"ref/respbody.xml\">\n<!ENTITY refreqflags SYSTEM \"ref/reqflags.xml\">\n<!ENTITY refreqtarget SYSTEM \"ref/reqtgt.xml\">\n<!ENTITY refctype SYSTEM \"ref/ctype.xml\">\n<!ENTITY refred SYSTEM \"ref/redir.xml\">\n<!ENTITY refsockssl SYSTEM \"ref/sockssl.xml\">\n<!ENTITY refstatus SYSTEM \"ref/status.xml\">\n<!ENTITY refgetst SYSTEM \"ref/getst.xml\">\n<!ENTITY refreqbody SYSTEM \"ref/reqbody.xml\">\n<!ENTITY refauth SYSTEM \"ref/auth.xml\">\n<!ENTITY refalloc SYSTEM \"ref/alloc.xml\">\n<!ENTITY refbuf SYSTEM \"ref/buf.xml\">\n<!ENTITY refbufcr SYSTEM \"ref/bufcr.xml\">\n<!ENTITY refbufapp SYSTEM \"ref/bufapp.xml\">\n<!ENTITY refbufdest SYSTEM \"ref/bufdest.xml\">\n<!ENTITY refbufutil SYSTEM \"ref/bufutil.xml\">\n<!ENTITY refhash SYSTEM \"ref/hash.xml\">\n<!ENTITY refnonce SYSTEM \"ref/nonce.xml\">\n<!ENTITY refparam SYSTEM \"ref/param.xml\">\n<!ENTITY reflower SYSTEM \"ref/lower.xml\">\n<!ENTITY reftok SYSTEM \"ref/tok.xml\">\n<!ENTITY refshave SYSTEM \"ref/shave.xml\">\n<!ENTITY refvers SYSTEM \"ref/vers.xml\">\n<!ENTITY refinit SYSTEM \"ref/init.xml\">\n<!ENTITY refi18n SYSTEM \"ref/i18n.xml\">\n<!ENTITY reffeat SYSTEM \"ref/feat.xml\">\n<!ENTITY refresolve SYSTEM \"ref/resolve.xml\">\n<!ENTITY refiaddr SYSTEM \"ref/iaddr.xml\">\n<!ENTITY refclicert SYSTEM \"ref/clicert.xml\">\n<!ENTITY refxml SYSTEM \"ref/xml.xml\">\n<!ENTITY refxmlreq SYSTEM \"ref/xmlreq.xml\">\n]>\n\n<book>\n  <bookinfo>\n    <title>neon HTTP/WebDAV client library</title>\n    <author>\n      <personname>\n        <firstname>Joe</firstname><surname>Orton</surname>\n      </personname>\n    </author>\n    &copyright;\n\n    <legalnotice>\n\n      <para>This document is free documentation; you can redistribute\n      it and/or modify it under the terms of the <ulink\n      url=\"http://www.gnu.org/copyleft/gpl.html\">GNU General Public\n      License</ulink> as published by the Free Software Foundation;\n      either version 2 of the License, or (at your option) any later\n      version.</para>\n    \n      <para>This document is distributed in the hope that it will be\n      useful, but <emphasis>without any warranty</emphasis>; without\n      even the implied warranty of\n      <emphasis>merchantability</emphasis> or <emphasis>fitness for a\n      particular purpose</emphasis>.  See the GNU General Public\n      License for more details.</para>\n\n      <para>You should have received a copy of the GNU General Public\n      License along with this program; if not, write to the Free\n      Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,\n      USA.</para>\n\n    </legalnotice>\n\n  </bookinfo>\n  \n  <chapter id=\"intro\">\n    <title>Introduction</title>\n\n    <para>This chapter provides an introduction to neon, giving an\noverview of the range of features offered, and some general guidelines\nfor using the neon API.</para>\n    \n    <para>neon aims to provide a modern, flexible, and simple API\nin the C programming language for implementing HTTP and WebDAV\nsupport.  The WebDAV functionality is entirely separate from the basic\nHTTP functionality; neon can be used simply as an HTTP client library,\nignoring the WebDAV support if desired.</para>\n\n    &section.features;\n\n    &section.using;\n    \n    &section.security;\n\n  </chapter>\n \n  <chapter id=\"api\">\n    <title>The &neon; C language interface</title>\n\n    <para>The documentation for the &neon; interface is split between\n    this chapter, which gives a broad introduction to the abstractions\n    exposed by the library, and <xref linkend=\"ref\"/>, which gives a\n    function-by-function breakdown of the interface.</para>\n\n    &section.xml;\n\n<!-- &section.ssl; -->\n\n  </chapter>\n \n  <reference id=\"ref\">\n\n    <!-- these are used in the man page header/footers -->\n    <referenceinfo>\n      <title>neon API reference</title>\n      <date>&date;</date>\n      <productname>neon</productname>\n      <productnumber>&version;</productnumber>\n      &copyright;\n    </referenceinfo>\n    \n    <title>neon API reference</title>\n\n    &refneon; <!-- neon -->\n    &refconfig; <!-- neon-config -->\n\n    &refresolve; <!-- ne_addr_resolve -->\n    &refbuf; <!-- ne_buffer -->\n    &refbufapp; <!-- ne_buffer_append -->\n    &refbufutil; <!-- ne_buffer_clear -->\n    &refbufcr; <!-- ne_buffer_create -->\n    &refbufdest; <!-- ne_buffer_destroy -->\n    &refhash; <!-- ne_strhash -->\n    &refnonce; <!-- ne_mknonce -->\n    &refparam; <!-- ne_strparam -->\n    &reflower; <!-- ne_strlower -->\n    &referr; <!-- ne_get_error -->\n    &refgetst; <!-- ne_get_status -->\n    &reffeat; <!-- ne_has_support -->\n    &refi18n; <!-- ne_i18n_init -->\n    &refiaddr; <!-- ne_iaddr_make -->\n    &refalloc; <!-- ne_malloc -->\n    &refsess; <!-- ne_session_create -->\n    &refproxy; <!-- ne_session_proxy -->\n    &refsessflags; <!-- ne_set_session_flag -->\n    &refreq; <!-- ne_request_create -->\n    &refreqhdr; <!-- ne_add_request_header -->\n    &refresphdr; <!-- ne_add_request_header -->\n    &refrespbody; <!-- ne_read_response_to_fd -->\n    &refopts; <!-- ne_set_useragent -->\n    &refreqflags; <!-- ne_set_request_flag -->\n    &refreqbody; <!-- ne_set_request_body_buffer -->\n    &refreqtarget; <!-- ne_get_request_target -->\n    &refctype; <!-- ne_get_content_type -->\n    &refred; <!-- ne_redirect_register -->\n    &refauth; <!-- ne_set_server_auth -->\n    &refshave; <!-- ne_shave -->\n    &refinit; <!-- ne_sock_init -->\n    &refsslcert; <!-- ne_ssl_cert_identity -->\n    &refsslcert2; <!-- ne_ssl_cert_cmp -->\n    &refsslcertio; <!-- ne_ssl_cert_read -->\n    &refssldname; <!-- ne_ssl_dname -->\n    &refssltrust; <!-- ne_ssl_load_ca -->\n    &refsslproto; <!-- ne_ssl_proto_name -->\n    &refsslvers; <!-- ne_ssl_set_protovers -->\n    &refsslvfy; <!-- ne_ssl_set_verify -->\n    &refsslctx; <!-- ne_ssl_context_* -->\n    &refsockssl; <!-- ne_sock_ssl*_* -->\n    &refclicert; <!-- ne_ssl_client_cert -->\n    &refstatus; <!-- ne_status -->\n    &reftok; <!-- ne_token -->\n    &refvers; <!-- ne_version_match -->\n    &refxml; <!-- ne_xml_parser -->\n    &refxmlreq; <!-- ne_xml_parse_response -->\n\n    <!-- REFEND -->\n    <!-- ******************************************************************* -->\n\n  </reference>\n\n&biblio;\n\n</book>\n"
  },
  {
    "path": "doc/parsing-xml.txt",
    "content": "\nRequirements for XML parsing in neon\n------------------------------------\n\nBefore describing the interface given in neon for parsing XML, here\nare the requirements which it must satisfy:\n\n 1. to support using either libxml or expat as the underlying parser\n 2. to allow \"independent\" sections to handle parsing one XML\n    document\n 3. to map element namespaces/names to an integer for easier\n    comparison.\n\nA description of requirement (2) is useful since it is the \"hard\"\nrequirement, and adds most of the complexity of interface: WebDAV\nPROPFIND responses are made up of a large boilerplate XML\n\n <multistatus><response><propstat><prop>...</prop></propstat> etc.\n\nneon should handle the parsing of these standard elements, and expose\nthe meaning of the response using a convenient interface.  But, within\nthe <prop> elements, there may also be fragments of XML: neon can\nnever know how to parse these, since they are property- and hence\napplication-specific. The simplest example of this is the\nDAV:resourcetype property.\n\nSo there is requirement (2) that two \"independent\" sections of code\ncan handle the parsing of one XML document.\n\nCallback-based XML parsing\n--------------------------\n\nThere are two ways of parsing XML documents commonly used:\n\n 1. Build an in-memory tree of the document\n 2. Use callbacks\n\nWhere practical, using callbacks is more efficient than building a\ntree, so this is what neon uses.  The standard interface for\ncallback-based XML parsing is called SAX, so understanding the SAX\ninterface is useful to understanding the XML parsing interface\nprovided by neon.\n\nThe SAX interface works by registering callbacks which are called *as\nthe XML is parsed*. The most important callbacks are for 'start\nelement' and 'end element'. For instance, if the XML document below is\nparsed by a SAX-like interface:\n\n  <hello>\n    <foobar></foobar>\n  </hello>\n\nSay we have registered callbacks \"startelm\" for 'start element' and\n\"endelm\" for 'end element'.  Simplified somewhat, the callbacks will\nbe called in this order, with these arguments:\n\n 1. startelm(\"hello\")\n 2. startelm(\"foobar\")\n 3. endelm(\"foobar\")\n 4. endelm(\"hello\")\n\nSee the expat 'xmlparse.h' header for a more complete definition of a\nSAX-like interface.\n\nThe hip_xml interface\n---------------------\n\nThe hip_xml interface satisfies requirement (2) by introducing the\n\"handler\" concept. A handler is made up of these things:\n\n - a set of XML elements\n - a callback to validate an element\n - a callback which is called when an element is opened\n - a callback which is called when an element is closed\n - (optionally, a callback which is called for CDATA)\n\nRegistering a handler essentially says:\n\n \"If you encounter any of this set of elements, I want these\n  callbacks to be called.\"\n\nHandlers are kept in a STACK inside hip_xml.  The first handler\nregistered becomes the BASE of the stack, subsequent handlers are\nPUSHed on top.\n\nDuring XML parsing, the handler which is used for an XML element is\nrecorded.  When a new element is started, the search for a handler for\nthis element begins at the handler used for the parent element, and\ncarries on up the stack.  For the root element, the search always\nstarts at the BASE of the stack.\n\nA user's guide to hip_xml\n-------------------------\n\nThe first thing to do when using hip_xml is to know what set of XML\nelements you are going to be parsing.  This can usually be done by\nlooking at the DTD provided for the documents you are going to be\nparsing.  The DTD is also very useful in writing the 'validate'\ncallback function, since it can tell you what parent/child pairs are\nvalid, and which aren't.\n\nIn this example, we'll parse XML documents which look like:\n\n<T:list-of-things xmlns:T=\"http://things.org/\">\n  <T:a-thing>foo</T:a-thing>\n  <T:a-thing>bar</T:a-thing>\n</T:list-of-things>\n\nSo, given the set of elements, declare the element id's and the\nelement array:\n\n#define ELM_listofthings (HIP_ELM_UNUSED)\n#define ELM_a_thing (HIP_ELM_UNUSED + 1)\n\nconst static struct my_elms[] = {\n   { \"http://things.org/\", \"list-of-things\", ELM_listofthings, 0 },\n   { \"http://things.org/\", \"a-thing\", ELM_a_thing, HIP_XML_CDATA },\n   { NULL }\n};\n\nThis declares we know about two elements: list-of-things, and a-thing,\nand that the 'a-thing' element contains character data.\n\nThe definition of the validation callback is very simple:\n\nstatic int validate(hip_xml_elmid parent, hip_xml_elmid child)\n{\n    /* Only allow 'list-of-things' as the root element. */\n    if (parent == HIP_ELM_root && child == ELM_listofthings ||\n        parent = ELM_listofthings && child == ELM_a_thing) {\n\treturn HIP_XML_VALID;\n    } else {\n        return HIP_XML_INVALID;\n    }\n}\n\nFor this example, we can ignore the start-element callback, and just\nuse the end-element callback:\n\nstatic int endelm(void *userdata, const struct hip_xml_elm *s,\n\t\t  const char *cdata)\n{\n    printf(\"Got a thing: %s\\n\", cdata);\n    return 0;\n}\n\nThis endelm callback just prints the cdata which was contained in the\n\"a-thing\" element.\n\nNow, on to parsing. A new parser object is created for parsing each\nXML document.  Creating a new parser object is as simple as:\n\n  hip_xml_parser *parser;\n\n  parser = hip_xml_create();\n\nNext register the handler, passing NULL as the start-element callback,\nand also as userdata, which we don't use here.\n\n  hip_xml_push_handler(parser, my_elms, \n\t\t       validate, NULL, endelm,\n\t\t       NULL);\n\nFinally, call hip_xml_parse, passing the chunks of XML document to the\nhip_xml as you get them. The output should be:\n\n  Got a thing: foo\n  Got a thing: bar\n\nfor the XML document.\n"
  },
  {
    "path": "doc/ref/alloc.xml",
    "content": "    <refentry id=\"refalloc\">\n\n      <refmeta>\n\t<refentrytitle>ne_malloc</refentrytitle>\n\t<manvolnum>3</manvolnum>\n      </refmeta>\n\n      <refnamediv>\n\t<refname id=\"ne_malloc\">ne_malloc</refname>\n\t<refname id=\"ne_calloc\">ne_calloc</refname>\n\t<refname id=\"ne_realloc\">ne_realloc</refname>\n\t<refname id=\"ne_strdup\">ne_strdup</refname>\n\t<refname id=\"ne_strndup\">ne_strndup</refname>\n        <refname id=\"ne_oom_callback\">ne_oom_callback</refname>\n\t<refpurpose>memory allocation wrappers</refpurpose>\n      </refnamediv>\n      \n      <refsynopsisdiv>\n\t\n\t<funcsynopsis>\n\n\t  <funcsynopsisinfo>#include &lt;ne_alloc.h&gt;</funcsynopsisinfo>\n\n\t  <funcprototype>\n\t    <funcdef>void *<function>ne_malloc</function></funcdef>\n\t    <paramdef>size_t <parameter>size</parameter></paramdef>\n\t  </funcprototype>\n\n\t  <funcprototype>\n\t    <funcdef>void *<function>ne_calloc</function></funcdef>\n\t    <paramdef>size_t <parameter>size</parameter></paramdef>\n\t  </funcprototype>\n\n\t  <funcprototype>\n\t    <funcdef>void *<function>ne_realloc</function></funcdef>\n\t    <paramdef>void *<parameter>size</parameter></paramdef>\n\t    <paramdef>size_t <parameter>len</parameter></paramdef>\n\t  </funcprototype>\n\n\t  <funcprototype>\n\t    <funcdef>char *<function>ne_strdup</function></funcdef>\n\t    <paramdef>const char *<parameter>s</parameter></paramdef>\n\t  </funcprototype>\n\n\t  <funcprototype>\n\t    <funcdef>char *<function>ne_strndup</function></funcdef>\n\t    <paramdef>const char *<parameter>s</parameter></paramdef>\n\t    <paramdef>size_t <parameter>size</parameter></paramdef>\n\t  </funcprototype>\n\n\t  <funcprototype>\n\t    <funcdef>void <function>ne_oom_callback</function></funcdef>\n\t    <paramdef>void (*<parameter>callback</parameter>)(void)</paramdef>\n\t  </funcprototype>\n\n\t</funcsynopsis>\n\t\n      </refsynopsisdiv>\n\n      <refsect1>\n\t<title>Description</title>\n\n\t<para>The functions <function>ne_malloc</function>,\n<function>ne_calloc</function>, <function>ne_realloc</function>,\n<function>ne_strdup</function> and <function>ne_strdnup</function>\nprovide wrappers for the equivalent functions in the standard C\nlibrary.  The wrappers provide the extra guarantee that if the C\nlibrary equivalent returns &null; when no memory is available, an\noptional callback will be called, and the library will then call\n<function>abort</function>().</para>\n\n\t<para><function>ne_oom_callback</function> registers a callback\nwhich will be invoked if an out of memory error is detected.</para>\n\n      </refsect1>\n\n      <refsect1>\n\t<title>Notes</title>\n\n\t<para>If the operating system uses optimistic memory\nallocation, the C library memory allocation routines will not return\n&null;, so it is not possible to gracefully handle memory allocation\nfailures.</para>\n\n      </refsect1>\n\n    </refentry>\n"
  },
  {
    "path": "doc/ref/auth.xml",
    "content": "    <refentry id=\"refauth\">\n\n      <refmeta>\n\t<refentrytitle>ne_set_server_auth</refentrytitle>\n\t<manvolnum>3</manvolnum>\n      </refmeta>\n\n      <refnamediv>\n\t<refname id=\"ne_set_server_auth\">ne_set_server_auth</refname>\n\t<refname id=\"ne_set_proxy_auth\">ne_set_proxy_auth</refname>\n\t<refname id=\"ne_forget_auth\">ne_forget_auth</refname>\n\t<refpurpose>register authentication callbacks</refpurpose>\n      </refnamediv>\n      \n      <refsynopsisdiv>\n\t\n\t<funcsynopsis>\n\n\t  <funcsynopsisinfo>#include &lt;ne_auth.h&gt;</funcsynopsisinfo>\n\n\t  <funcprototype>\n\t    <funcdef>typedef int (*<function>ne_auth_creds</function>)</funcdef>\n\t    <paramdef>void *<parameter>userdata</parameter></paramdef>\n\t    <paramdef>const char *<parameter>realm</parameter></paramdef>\n\t    <paramdef>int <parameter>attempt</parameter></paramdef>\n\t    <paramdef>char *<parameter>username</parameter></paramdef>\n\t    <paramdef>char *<parameter>password</parameter></paramdef>\n\t  </funcprototype>\n\n\t  <funcprototype>\n\t    <funcdef>void <function>ne_set_server_auth</function></funcdef>\n\t    <paramdef>ne_session *<parameter>session</parameter></paramdef>\n\t    <paramdef>ne_auth_creds <parameter>callback</parameter></paramdef>\n\t    <paramdef>void *<parameter>userdata</parameter></paramdef>\n\t  </funcprototype>\n\n\t  <funcprototype>\n\t    <funcdef>void <function>ne_set_proxy_auth</function></funcdef>\n\t    <paramdef>ne_session *<parameter>session</parameter></paramdef>\n\t    <paramdef>ne_auth_creds <parameter>callback</parameter></paramdef>\n\t    <paramdef>void *<parameter>userdata</parameter></paramdef>\n\t  </funcprototype>\n\n\t  <funcprototype>\n\t    <funcdef>void <function>ne_forget_auth</function></funcdef>\n\t    <paramdef>ne_session *<parameter>session</parameter></paramdef>\n\t  </funcprototype>\n\n\t</funcsynopsis>\n\t\n      </refsynopsisdiv>\n\n      <refsect1>\n\t<title>Description</title>\n\n\t<para>The <type>ne_auth_creds</type> function type defines a\ncallback which is invoked when a server or proxy server requires user\nauthentication for a particular request.  The\n<parameter>realm</parameter> string is supplied by the server. <!--\nFIXME --> The <parameter>attempt</parameter> is a counter giving the\nnumber of times the request has been retried with different\nauthentication credentials.  The first time the callback is invoked\nfor a particular request, <parameter>attempt</parameter> will be zero.</para>\n\n\t<para>To retry the request using new authentication\ncredentials, the callback should return zero, and the\n<parameter>username</parameter> and <parameter>password</parameter>\nbuffers must contain &nul;-terminated strings.  The\n<literal>NE_ABUFSIZ</literal> constant gives the size of these\nbuffers.</para>\n\n\t<tip>\n\t  <para>If you only wish to allow the user one attempt to enter\ncredentials, use the value of the <parameter>attempt</parameter>\nparameter as the return value of the callback.</para>\n\t</tip>\n\n\t<para>To abort the request, the callback should return a\nnon-zero value; in which case the contents of the\n<parameter>username</parameter> and <parameter>password</parameter>\nbuffers are ignored.</para>\n\n\t<para>The <function>ne_forget_auth</function> function can be\nused to discard the cached authentication credentials.</para>\n\n      </refsect1>\n\n      <refsect1>\n\t<title>Examples</title>\n\n\t<programlisting>\n/* Function which prompts for a line of user input: */\nextern char *prompt_for(const char *prompt);\n\nstatic int\nmy_auth(void *userdata, const char *realm, int attempts,\n        char *username, char *password)\n{\n   strncpy(username, prompt_for(\"Username: \"), NE_ABUFSIZ);\n   strncpy(password, prompt_for(\"Password: \"), NE_ABUFSIZ);\n   return attempts;\n}\n\nint main(...)\n{\n   &egsess;\n\n   ne_set_server_auth(sess, my_auth, NULL);\n\n   /* ... */\n}</programlisting>\n      </refsect1>\n\n    </refentry>\n"
  },
  {
    "path": "doc/ref/buf.xml",
    "content": "    <refentry id=\"refbuf\">\n\n      <refmeta>\n\t<refentrytitle>ne_buffer</refentrytitle>\n\t<manvolnum>3</manvolnum>\n      </refmeta>\n\n      <refnamediv>\n\t<refname id=\"ne_buffer\">ne_buffer</refname>\n\t<refpurpose>string buffer handling</refpurpose>\n      </refnamediv>\n      \n      <refsynopsisdiv>\n\n\t<funcsynopsis><funcsynopsisinfo>#include &lt;ne_string.h&gt;\n\ntypedef struct {\n    char *data;\n    size_t used;\n    size_t length;\n} <type>ne_buffer</type>;</funcsynopsisinfo></funcsynopsis>\n\n      </refsynopsisdiv>\n\n      <refsect1>\n\t<title>Description</title>\n\n\t<para>The <type>ne_buffer</type> type represents an expandable\nmemory buffer for holding &nul;-terminated strings.  The\n<structfield>data</structfield> field points to the beginning of the\nstring, the length of which is given by the\n<structfield>used</structfield> field.  The current size of memory\nallocated is given by the <structfield>length</structfield> field.  It\nis not recommended that the fields of a buffer are manipulated\ndirectly.  The <structfield>data</structfield> pointer may change when\nthe buffer is modified.</para>\n\n\t<para>A buffer is created using <xref\nlinkend=\"ne_buffer_create\"/> or <xref\nlinkend=\"ne_buffer_create_sized\"/>, and destroyed using <xref\nlinkend=\"ne_buffer_destroy\"/> or <xref linkend=\"ne_buffer_finish\"/>.\nThe functions <xref linkend=\"ne_buffer_append\"/>, <xref\nlinkend=\"ne_buffer_zappend\"/> and <xref linkend=\"ne_buffer_concat\"/> are\nused to append data to a buffer.</para>\n\n\t<para>If the string referenced by the\n<structfield>data</structfield> pointer is modified directly (rather\nthan using one of the functions listed above),\n<function>ne_buffer_altered</function> must be called.</para>\n\n      </refsect1>\n\n    </refentry>\n"
  },
  {
    "path": "doc/ref/bufapp.xml",
    "content": "    <refentry id=\"refbufapp\">\n\n      <refmeta>\n\t<refentrytitle>ne_buffer_append</refentrytitle>\n\t<manvolnum>3</manvolnum>\n      </refmeta>\n\n      <refnamediv>\n\t<refname id=\"ne_buffer_append\">ne_buffer_append</refname>\n\t<refname id=\"ne_buffer_zappend\">ne_buffer_zappend</refname>\n\t<refname id=\"ne_buffer_qappend\">ne_buffer_qappend</refname>\n\t<refname id=\"ne_buffer_concat\">ne_buffer_concat</refname>\n\t<refname id=\"ne_buffer_snprintf\">ne_buffer_snprintf</refname>\n\t<refpurpose>append data to a string buffer</refpurpose>\n      </refnamediv>\n      \n      <refsynopsisdiv>\n\t\n\t<funcsynopsis>\n\n\t  <funcsynopsisinfo>#include &lt;ne_string.h&gt;</funcsynopsisinfo>\n\n\t  <funcprototype>\n\t    <funcdef>void <function>ne_buffer_append</function></funcdef>\n\t    <paramdef>ne_buffer *<parameter>buf</parameter></paramdef>\n\t    <paramdef>const char *<parameter>string</parameter></paramdef>\n\t    <paramdef>size_t <parameter>len</parameter></paramdef>\n\t  </funcprototype>\n\n\t  <funcprototype>\n\t    <funcdef>void <function>ne_buffer_zappend</function></funcdef>\n\t    <paramdef>ne_buffer *<parameter>buf</parameter></paramdef>\n\t    <paramdef>const char *<parameter>string</parameter></paramdef>\n\t  </funcprototype>\n\n\t  <funcprototype>\n\t    <funcdef>void <function>ne_buffer_qappend</function></funcdef>\n\t    <paramdef>ne_buffer *<parameter>buf</parameter></paramdef>\n\t    <paramdef>const char *<parameter>string</parameter></paramdef>\n\t    <paramdef>size_t <parameter>len</parameter></paramdef>\n\t  </funcprototype>\n\n\t  <funcprototype>\n\t    <funcdef>void <function>ne_buffer_concat</function></funcdef>\n\t    <paramdef>ne_buffer *<parameter>buf</parameter></paramdef>\n\t    <paramdef>...</paramdef>\n\t  </funcprototype>\n\n\t  <funcprototype>\n\t    <funcdef>size_t <function>ne_buffer_snprintf</function></funcdef>\n\t    <paramdef>ne_buffer *<parameter>buf</parameter></paramdef>\n\t    <paramdef>size_t <parameter>max</parameter></paramdef>\n\t    <paramdef>const char *<parameter>format</parameter></paramdef>\n\t    <paramdef>...</paramdef>\n\t  </funcprototype>\n\t</funcsynopsis>\n\t\n      </refsynopsisdiv>\n\n      <refsect1>\n\t<title>Description</title>\n\n\t<para>The <function>ne_buffer_append</function> and\n<function>ne_buffer_zappend</function> functions append a string to\nthe end of a buffer; extending the buffer as necessary.  The\n<parameter>len</parameter> passed to\n<function>ne_buffer_append</function> specifies the length of the\nstring to append; there must be no &nul; terminator in the first\n<parameter>len</parameter> bytes of the string.\n<function>ne_buffer_zappend</function> must be passed a\n&nul;-terminated string.</para>\n\n\t<para>The <function>ne_buffer_qappend</function> function\n\tbehaves similarly to <function>ne_buffer_append</function>,\n\texcept that any non-ASCII characters or ASCII control\n\tcharacters are escaped using C-style hex escaping. For\n\texample, the C string <literal>\"foo&lt;TAB&gt;bar\"</literal>,\n\twhere TAB represents ASCII character 9, would be appended as\n\t<literal>\"foo\\x09bar\"</literal>. Any &nul; bytes within the\n\tlength specified are also escaped. This function is useful to\n\tmake strings from untrusted sources safe for logging or output\n\tin a user interface.</para>\n\n\t<para>The <function>ne_buffer_concat</function> function takes\n\ta variable-length argument list; each argument must be a\n\t<type>char *</type> pointer to a &nul;-terminated string.  A\n\t&null; pointer must be given as the last argument to mark the\n\tend of the list.  The strings are appended to the buffer in\n\tthe order given. None of the strings passed to\n\t<function>ne_buffer_concat</function> are modified.</para>\n\n<para>The <function>ne_buffer_snprintf</function> function behaves\nlike <function>snprintf</function>, appending the output string\nformatted according to the <parameter>format</parameter> parameter.\nAt most <parameter>max</parameter> bytes are written including the\ntrailing &nul; terminator.</para>\n\n      </refsect1>\n\n      <refsect1>\n\t<title>Return value</title>\n\n        <para>The <function>ne_buffer_snprintf</function> function\n        returns the number of bytes appended\n        <emphasis>excluding</emphasis> the trailing &nul;\n        terminator.</para>\n      </refsect1>\n\n      <refsect1>\n\t<title>Examples</title>\n\n\t<para>The following code will output \"<literal>Hello, world.\nAnd goodbye.</literal>\".</para>\n\t\n\t<programlisting>ne_buffer *buf = ne_buffer_create();\nne_buffer_zappend(buf, \"Hello\");\nne_buffer_concat(buf, \", world. \", \"And \", NULL);\nne_buffer_snprintf(buf, 10, \"%s.\", \"goodbye\");\nputs(buf->data);\nne_buffer_destroy(buf);</programlisting>\n      </refsect1>\n\n      <refsect1>\n\t<title>See also</title>\n\n\t<para><xref linkend=\"ne_buffer\"/>, <xref linkend=\"ne_buffer_create\"/>,\n<xref linkend=\"ne_buffer_destroy\"/></para>\n      </refsect1>\n\n    </refentry>\n"
  },
  {
    "path": "doc/ref/bufcr.xml",
    "content": "    <refentry id=\"refbufcr\">\n\n      <refmeta>\n\t<refentrytitle>ne_buffer_create</refentrytitle>\n\t<manvolnum>3</manvolnum>\n      </refmeta>\n\n      <refnamediv>\n\t<refname id=\"ne_buffer_create\">ne_buffer_create</refname>\n\t<refname id=\"ne_buffer_create_sized\">ne_buffer_ncreate</refname>\n\t<refpurpose>create a string buffer</refpurpose>\n      </refnamediv>\n      \n      <refsynopsisdiv>\n\t\n\t<funcsynopsis>\n\n\t  <funcsynopsisinfo>#include &lt;ne_alloc.h&gt;</funcsynopsisinfo>\n\n\t  <funcprototype>\n\t    <funcdef>ne_buffer *<function>ne_buffer_create</function></funcdef>\n\t    <void/>\n\t  </funcprototype>\n\n\t  <funcprototype>\n\t    <funcdef>ne_buffer *<function>ne_buffer_ncreate</function></funcdef>\n\t    <paramdef>size_t <parameter>size</parameter></paramdef>\n\t  </funcprototype>\n\n\t</funcsynopsis>\n\t\n      </refsynopsisdiv>\n\n      <refsect1>\n\t<title>Description</title>\n\n\t<para><function>ne_buffer_create</function> creates a new\nbuffer object, with an implementation-defined initial size.\n<function>ne_buffer_ncreate</function> creates an\n<type>ne_buffer</type> where the minimum initial size is given in the\n<parameter>size</parameter> parameter.  The buffer created will\ncontain the empty string (<literal>\"\"</literal>).</para>\n\n      </refsect1>\n\n      <refsect1>\n\t<title>Return value</title>\n\n\t<para>Both functions return a pointer to a new buffer object,\nand never &null;.</para>\n\n       </refsect1>\n\n      <refsect1>\n\t<title>See also</title>\n\n\t<para><xref linkend=\"ne_buffer\"/></para>\n      </refsect1>\n\n    </refentry>\n"
  },
  {
    "path": "doc/ref/bufdest.xml",
    "content": "    <refentry id=\"refbufdest\">\n\n      <refmeta>\n\t<refentrytitle>ne_buffer_destroy</refentrytitle>\n\t<manvolnum>3</manvolnum>\n      </refmeta>\n\n      <refnamediv>\n\t<refname id=\"ne_buffer_destroy\">ne_buffer_destroy</refname>\n\t<refname id=\"ne_buffer_finish\">ne_buffer_finish</refname>\n\t<refpurpose>destroy a buffer object</refpurpose>\n      </refnamediv>\n      \n      <refsynopsisdiv>\n\t\n\t<funcsynopsis>\n\n\t  <funcsynopsisinfo>#include &lt;ne_string.h&gt;</funcsynopsisinfo>\n\n\t  <funcprototype>\n\t    <funcdef>void <function>ne_buffer_destroy</function></funcdef>\n\t    <paramdef>ne_buffer *<parameter>buf</parameter></paramdef>\n\t  </funcprototype>\n\n\t  <funcprototype>\n\t    <funcdef>char *<function>ne_buffer_finish</function></funcdef>\n\t    <paramdef>ne_buffer *<parameter>buf</parameter></paramdef>\n\t  </funcprototype>\n\n\t</funcsynopsis>\n\t\n      </refsynopsisdiv>\n\n      <refsect1>\n\t<title>Description</title>\n\n\t<para><function>ne_buffer_destroy</function> frees all memory\nassociated with the buffer.  <function>ne_buffer_finish</function>\nfrees the buffer structure, but not the actual string stored in the\nbuffer, which is returned and must be <function>free</function>()d by\nthe caller.</para>\n\n\t<para>Any use of the buffer object after calling either of these\nfunctions gives undefined behaviour.</para>\n\n      </refsect1>\n\n      <refsect1>\n\t<title>Return value</title>\n\n\t<para><function>ne_buffer_finish</function> returns the\n<function>malloc</function>-allocated string stored in the buffer.</para>\n\n      </refsect1>\n\n      <refsect1>\n\t<title>Examples</title>\n\n\t<para>An example use of <function>ne_buffer_finish</function>;\nthe <function>duplicate</function> function returns a string made up of \n<parameter>n</parameter> copies of <parameter>str</parameter>:</para>\n\n\t<programlisting>static char *duplicate(int n, const char *str)\n{\n  ne_buffer *buf = ne_buffer_create();\n  while (n--) {\n    ne_buffer_zappend(buf, str);\n  }\n  return ne_buffer_finish(buf);\n}</programlisting>\n\n      </refsect1>\n\n      <refsect1>\n\t<title>See also</title>\n\n\t<para><xref linkend=\"ne_buffer\"/>, <xref linkend=\"ne_buffer_create\"/>,\n<xref linkend=\"ne_buffer_zappend\"/></para>\n      </refsect1>\n\n    </refentry>\n"
  },
  {
    "path": "doc/ref/bufutil.xml",
    "content": "    <refentry id=\"refbufutil\">\n\n      <refmeta>\n\t<refentrytitle>ne_buffer_clear</refentrytitle>\n\t<manvolnum>3</manvolnum>\n      </refmeta>\n\n      <refnamediv>\n\t<refname id=\"ne_buffer_clear\">ne_buffer_clear</refname>\n\t<refname id=\"ne_buffer_grow\">ne_buffer_grow</refname>\n\t<refname id=\"ne_buffer_altered\">ne_buffer_altered</refname>\n\t<refpurpose>clear, grow, or mark as altered a string buffer</refpurpose>\n      </refnamediv>\n      \n      <refsynopsisdiv>\n\t\n\t<funcsynopsis>\n\n\t  <funcsynopsisinfo>#include &lt;ne_string.h&gt;</funcsynopsisinfo>\n\n\t  <funcprototype>\n\t    <funcdef>void <function>ne_buffer_clear</function></funcdef>\n\t    <paramdef>ne_buffer *<parameter>buf</parameter></paramdef>\n\t  </funcprototype>\n\n\t  <funcprototype>\n\t    <funcdef>void <function>ne_buffer_altered</function></funcdef>\n\t    <paramdef>ne_buffer *<parameter>buf</parameter></paramdef>\n\t  </funcprototype>\n\n\t  <funcprototype>\n\t    <funcdef>void <function>ne_buffer_grow</function></funcdef>\n\t    <paramdef>ne_buffer *<parameter>buf</parameter></paramdef>\n\t    <paramdef>size_t <parameter>size</parameter></paramdef>\n\t  </funcprototype>\n\n\t</funcsynopsis>\n\t\n      </refsynopsisdiv>\n\n      <refsect1>\n\t<title>Description</title>\n\n\t<para>The <function>ne_buffer_clear</function> function sets\nthe string stored in <parameter>buf</parameter> to be the empty string\n(<literal>\"\"</literal>).</para>\n\n\t<para>The <function>ne_buffer_altered</function> function must\nbe used after the string stored in the buffer\n<parameter>buf</parameter> is modified by directly rather than using\n<xref linkend=\"ne_buffer_append\"/>, <xref linkend=\"ne_buffer_zappend\"/> \nor <xref linkend=\"ne_buffer_concat\"/>.</para>\n\n\t<para>The <function>ne_buffer_grow</function> function\nensures that at least <parameter>size</parameter> bytes are allocated\nfor the string; this can be used if a large amount of data is going to\nbe appended to the buffer and may result in more efficient memory\nallocation.</para>\n\n      </refsect1>\n\n    </refentry>\n"
  },
  {
    "path": "doc/ref/clicert.xml",
    "content": "<refentry id=\"refclicert\">\n\n  <refmeta>\n    <refentrytitle>ne_ssl_client_cert</refentrytitle>\n    <manvolnum>3</manvolnum>\n  </refmeta>\n\n  <refnamediv>\n    <refname id=\"ne_ssl_clicert_read\">ne_ssl_clicert_read</refname>\n    <refname id=\"ne_ssl_clicert_import\">ne_ssl_clicert_import</refname>\n    <refname id=\"ne_ssl_clicert_fromuri\">ne_ssl_clicert_fromuri</refname>\n    <refname id=\"ne_ssl_clicert_name\">ne_ssl_clicert_name</refname>\n    <refname id=\"ne_ssl_clicert_encrypted\">ne_ssl_clicert_encrypted</refname>\n    <refname id=\"ne_ssl_clicert_decrypt\">ne_ssl_clicert_decrypt</refname>\n    <refname id=\"ne_ssl_clicert_owner\">ne_ssl_clicert_owner</refname>\n    <refname id=\"ne_ssl_clicert_free\">ne_ssl_clicert_free</refname>\n    <refpurpose>SSL client certificate handling</refpurpose>\n  </refnamediv>\n  \n  <refsynopsisdiv>\n\n    <funcsynopsis>\n\n      <funcsynopsisinfo>#include &lt;ne_ssl.h&gt;</funcsynopsisinfo>\n\n      <funcprototype>\n        <funcdef>ne_ssl_client_cert *<function>ne_ssl_clicert_read</function></funcdef>\n        <paramdef>const char *<parameter>filename</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>ne_ssl_client_cert *<function>ne_ssl_clicert_import</function></funcdef>\n        <paramdef>const unsigned char *<parameter>filename</parameter></paramdef>\n        <paramdef>size_t <parameter>buflen</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>ne_ssl_client_cert *<function>ne_ssl_clicert_fromuri</function></funcdef>\n        <paramdef>const char *<parameter>uri</parameter></paramdef>\n        <paramdef>unsigned <parameter>flags</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>const char *<function>ne_ssl_clicert_name</function></funcdef>\n        <paramdef>const ne_ssl_client_cert *<parameter>ccert</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>int <function>ne_ssl_clicert_encrypted</function></funcdef>\n        <paramdef>const ne_ssl_client_cert *<parameter>ccert</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>int <function>ne_ssl_clicert_decrypt</function></funcdef>\n        <paramdef>ne_ssl_client_cert *<parameter>ccert</parameter></paramdef>\n        <paramdef>const char *<parameter>password</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>const ne_ssl_certificate *<function>ne_ssl_clicert_owner</function></funcdef>\n        <paramdef>const ne_ssl_client_cert *<parameter>ccert</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>void <function>ne_ssl_clicert_free</function></funcdef>\n        <paramdef>ne_ssl_client_cert *<parameter>ccert</parameter></paramdef>\n      </funcprototype>\n\n    </funcsynopsis>\n\n  </refsynopsisdiv>\n\n  <refsect1>\n    <title>Description</title>\n\n    <para>The <function>ne_ssl_clicert_read</function> function reads\n    a <firstterm>client certificate</firstterm> from a\n    PKCS#12-formatted file, and returns an\n    <type>ne_ssl_client_cert</type> object. The\n    <function>ne_ssl_clicert_import</function> function reads a client\n    certificate from a memory buffer using the PKCS#12 format. The\n    <function>ne_ssl_clicert_fromuri</function> function loads a\n    client certificate from a URI. URI schemes supported are defined\n    by the SSL/TLS toolkit, and may include <ulink url=\"https://www.rfc-editor.org/rfc/rfc7512.html\">PKCS#11 URIs</ulink>.</para>\n\n    <para>A <type>ne_ssl_client_cert</type> object represents both a\n    client certificate and the associated private key; the term\n    \"<glossterm>client certificate</glossterm>\" is used here to refer to\n    this pair. A client certificate object loaded by any of the above\n    functions can be in one of two states:\n    <emphasis>encrypted</emphasis> or <emphasis>decrypted</emphasis>.\n    The <function>ne_ssl_clicert_encrypted</function> function will\n    return non-zero if the client certificate is in the\n    <emphasis>encrypted</emphasis> state.</para>\n\n    <para>A client certificate <emphasis>must</emphasis> be in the\n    decrypted state before it is associated with a\n    session. <function>ne_ssl_clicert_decrypt</function> can be used\n    to decrypt a client certificate using the appropriate password.\n    This function must only be called if the object is in the\n    <emphasis>encrypted</emphasis> state; if decryption fails, the\n    certificate state does not change, so decryption can be attempted\n    more than once using different passwords.</para>\n\n    <para>A client certificate can be given a \"friendly name\" when it\n    is created; <function>ne_ssl_clicert_name</function> will return\n    this name (or &null; if no friendly name was specified).\n    <function>ne_ssl_clicert_name</function> can be used when the\n    client certificate is in either the encrypted or decrypted state,\n    and will return the same string for the lifetime of the\n    object.</para>\n\n    <para>The function <function>ne_ssl_clicert_owner</function>\n    returns the certificate part of the client certificate; it must\n    only be called if the client certificate is in the\n    <emphasis>decrypted</emphasis> state.</para>\n\n    <para>When the client certificate object is no longer needed, the\n    <function>ne_ssl_clicert_free</function> function should be used\n    to destroy the object.</para>\n\n  </refsect1>\n\n  <refsect1>\n    <title>Return value</title>\n\n    <para><function>ne_ssl_clicert_read</function>,\n    <function>ne_ssl_clicert_import</function> and\n    <function>ne_ssl_clicert_fromuri</function> all return a client\n    certificate object, or &null; if the certificate could not be\n    read/imported.  <function>ne_ssl_clicert_encrypted</function>\n    returns zero if the object is in the decrypted state, or non-zero\n    if it is in the encrypted\n    state. <function>ne_ssl_clicert_name</function> returns a\n    &nul;-terminated friendly name string, or &null;.\n    <function>ne_ssl_clicert_owner</function> returns a certificate\n    object.</para>\n\n  </refsect1>\n\n  <refsect1>\n    <title>Examples</title>\n\n    <para>The following code reads a client certificate and decrypts\n    it if necessary, then loads it into an HTTP session.</para>\n\n    <programlisting>ne_ssl_client_cert *ccert;\n\nccert = ne_ssl_clicert_read(\"/path/to/client.p12\");\n\nif (ccert == NULL) {\n   /* handle error... */\n} else if (ne_ssl_clicert_encrypted(ccert)) {\n   char *password = prompt_for_password();\n\n   if (ne_ssl_clicert_decrypt(ccert, password)) {\n      /* could not decrypt! handle error... */\n   }\n}\n\nne_ssl_set_clicert(sess, ccert);\n</programlisting>\n\n  </refsect1>\n\n  <refsect1>\n    <title>History</title>\n\n    <para><function>ne_ssl_clicert_import</function> was added in\n    &neon; 0.30.0. <function>ne_ssl_clicert_fromuri</function> was\n    added in &neon; 0.35.0.</para>\n  </refsect1>\n\n  <refsect1>\n    <title>See also</title>\n\n    <para><xref linkend=\"ne_ssl_cert_read\"/></para>\n  </refsect1>\n\n</refentry>\n\n"
  },
  {
    "path": "doc/ref/config.xml",
    "content": "    <refentry id=\"refconfig\">\n\n      <refentryinfo><title>neon</title></refentryinfo>\n\n      <refmeta>\n\t<refentrytitle>neon-config</refentrytitle>\n\t<manvolnum>1</manvolnum>\n      </refmeta>\n\n      <refnamediv>\n\t<refname id=\"neon-config\">neon-config</refname>\n\n\t<refpurpose>script providing information about installed copy\n\tof neon library</refpurpose>\n      </refnamediv>\n\n      <refsynopsisdiv>\n\n\t<cmdsynopsis>\n\t  <command>neon-config</command>\n\t  <arg choice=\"opt\"><option>--prefix</option></arg>\n\t  <group>\n\t    <arg><option>--cflags</option></arg>\n\t    <arg><option>--libs</option></arg>\n\t    <arg><option>--la-file</option></arg>\n\t    <arg><option>--support</option> <replaceable>feature</replaceable></arg>\n\t    <arg><option>--help</option></arg>\n\t    <arg><option>--version</option></arg>\n\t  </group>\n\t</cmdsynopsis>\n\n      </refsynopsisdiv>\n\n      <refsect1>\n\t<title>Description</title>\n\n\t<para>The <command>neon-config</command> script provides\ninformation about an installed copy of the neon library.  The\n<option>--cflags</option> and <option>--libs</option> options instruct\nhow to compile and link an application against the library; the\n<option>--version</option> and <option>--support</option> options can\nhelp determine whether the library meets the applications\nrequirements.</para>\n\n      </refsect1>\n\n      <refsect1>\n\t<title>Options</title>\n\n\t<variablelist>\n\n\t  <varlistentry>\n\t    <term><option>--cflags</option></term>\n\t    <listitem><simpara>Print the flags which should be passed to\nthe C compiler when compiling object files, when the object files use\nneon header files.</simpara></listitem>\n\t  </varlistentry>\n\n\t  <varlistentry>\n\t    <term><option>--libs</option></term>\n\t    <listitem><simpara>Print the flags which should be passed to\nthe linker when linking an application which uses the neon\nlibrary</simpara></listitem>\n\t  </varlistentry>\n\n\t  <varlistentry>\n\t    <term><option>--la-file</option></term>\n\t    <listitem><simpara>Print the location of the libtool library\nscript, <filename>libneon.la</filename>, which can be used to link against\n&neon; by applications using libtool.</simpara></listitem>\n\t  </varlistentry>\n\n\t  <varlistentry>\n\t    <term><option>--version</option></term>\n\t    <listitem><simpara>Print the version of the library</simpara></listitem>\n\t  </varlistentry>\n\n\t  <varlistentry>\n\t    <term><option>--prefix</option> <replaceable>dir</replaceable></term>\n\t    <listitem><simpara>If <replaceable>dir</replaceable> is given; relocate output of\n<option>--cflags</option> and <option>--libs</option> as if neon was\ninstalled in given prefix directory.  Otherwise, print the\ninstallation prefix of the library.</simpara></listitem>\n\t  </varlistentry>\n\n\t  <varlistentry>\n\t    <term><option>--support</option> <replaceable>feature</replaceable></term>\n\t    <listitem><simpara>The script exits with success if\n<replaceable>feature</replaceable> is supported by the\nlibrary.</simpara></listitem>\n          </varlistentry>\n\n\t  <varlistentry>\n\t    <term><option>--help</option></term>\n\t    <listitem><simpara>Print help message; includes list of known\n\t    features and whether they are supported or not.</simpara></listitem>\n\t  </varlistentry>\n\n\t</variablelist>\n\n      </refsect1>\n\n      <refsect1>\n\t<title>Example</title>\n\n\t<para>Below is a Makefile fragment which could be used to\nbuild an application against an installed neon library, when the\n<command>neon-config</command> script can be found in\n<envar>$PATH</envar>.</para>\n\n\t<programlisting>CFLAGS = `neon-config --cflags`\nLIBS = `neon-config --libs`\nOBJECTS = myapp.o\nTARGET = myapp\n\n$(TARGET): $(OBJECTS)\n\t$(CC) $(LDFLAGS) -o $(TARGET) $(OBJECTS) $(LIBS)\n\nmyapp.o: myapp.c\n\t$(CC) $(CFLAGS) -c myapp.c -o myapp.o</programlisting>\n\n       </refsect1>\n\n    </refentry>\n"
  },
  {
    "path": "doc/ref/ctype.xml",
    "content": "<refentry id=\"refgetctype\">\n\n  <refmeta>\n    <refentrytitle>ne_get_content_type</refentrytitle>\n    <manvolnum>3</manvolnum>\n  </refmeta>\n\n  <refnamediv>\n    <refname id=\"ne_get_content_type\">ne_get_content_type</refname>\n    <refpurpose>retrieve content type of response</refpurpose>\n  </refnamediv>\n\n  <refsynopsisdiv>\n    <funcsynopsis>\n      <funcsynopsisinfo>#include &lt;ne_basic.h&gt;\n\ntypedef struct {\n    const char *type, *subtype;\n    const char *charset;\n    char *value;\n} <type>ne_content_type;</type></funcsynopsisinfo>\n\n      <funcprototype>\n        <funcdef>int <function>ne_get_content_type</function></funcdef>\n        <paramdef>ne_request *<parameter>req</parameter></paramdef>\n        <paramdef>ne_content_type *<parameter>ctype</parameter></paramdef>\n      </funcprototype>\n    </funcsynopsis>\n  </refsynopsisdiv>\n\n  <refsect1>\n    <title>Description</title>\n\n    <para>The <function>ne_get_content_type</function> function retrieves\n    and parses the <literal>Content-Type</literal> header from the response\n    to request <parameter>req</parameter>.  If successful, all fields of\n    the <parameter>ctype</parameter> structure are set (and are never\n    &null;).  The <structfield>value</structfield> field must be freed by\n    the caller using <function>free</function> after use.</para>\n\n  </refsect1>\n\n  <refsect1>\n    <title>Return value</title>\n\n    <para><function>ne_get_content_type</function> returns zero if the\n    response had a valid <literal>Content-Type</literal> header, or\n    non-zero on error.  On error, the <parameter>ctype</parameter>\n    structure is not altered.</para>\n\n  </refsect1>\n\n  <refsect1>\n    <title>History</title>\n\n    <para>A default <structfield>charset</structfield> value was\n    returned for <literal>text/xml</literal> content-types in &neon;\n    0.36.0 and earlier; later versions use no default (per <ulink\n    url=\"https://www.rfc-editor.org/rfc/rfc7303\">RFC\n    7303</ulink>).</para>\n  </refsect1>\n\n  <refsect1>\n    <title>See also</title>\n\n    <para><xref linkend=\"ne_xml_dispatch_request\"/>, <xref linkend=\"ne_request_dispatch\"/></para>\n  </refsect1>\n\n</refentry>\n"
  },
  {
    "path": "doc/ref/err.xml",
    "content": "    <refentry id=\"referr\">\n\n      <refmeta>\n\t<refentrytitle>ne_get_error</refentrytitle>\n\t<manvolnum>3</manvolnum>\n      </refmeta>\n\n      <refnamediv>\n\t<refname id=\"ne_get_error\">ne_get_error</refname>\n\t<refname id=\"ne_set_error\">ne_set_error</refname>\n\t<refpurpose>error handling for HTTP sessions</refpurpose>\n      </refnamediv>\n      \n      <refsynopsisdiv>\n\t\n\t<funcsynopsis>\n\n\t  <funcsynopsisinfo>#include &lt;ne_session.h&gt;</funcsynopsisinfo>\n\n\t  <funcprototype>\n\t    <funcdef>const char *<function>ne_get_error</function></funcdef>\n\t    <paramdef>ne_sesssion *<parameter>session</parameter></paramdef>\n\t  </funcprototype>\n\n\t  <funcprototype>\n\t    <funcdef>void <function>ne_set_error</function></funcdef>\n\t    <paramdef>ne_sesssion *<parameter>session</parameter></paramdef>\n\t    <paramdef>const char *<parameter>format</parameter></paramdef>\n\t    <paramdef>...</paramdef>\n\t  </funcprototype>\n\n\t</funcsynopsis>\n\t\n      </refsynopsisdiv>\n      \n      <refsect1>\n\t<title>Description</title>\n\n\t<para>The session error string is used to store any\nhuman-readable error information associated with any errors which\noccur whilst using the HTTP session.</para>\n\n\t<para>The <function>ne_get_error</function> function returns\n\tthe current session error string.  This string persists only\n\tuntil it is changed by a subsequent operation on the session.\n\tIf localisation was enabled at build time, and if necessary\n\tenabled at run-time if necessary using <xref\n\tlinkend=\"ne_i18n_init\"/>, the returned string may have been\n\ttranslated into the user's current locale.</para>\n\n        <para>The <function>ne_set_error</function> function can be\n        used to set a new session error string, using a\n        <function>printf</function>-style format string\n        interface.</para>\n\n      </refsect1>\n\n      <refsect1>\n        <title>Return value</title>\n\n        <para><function>ne_set_error</function> returns a constant\n        &nul;-terminated string.  In the default English locale, the\n        returned string will <emphasis>not</emphasis> have a\n        terminating <quote>.</quote> period character.</para>\n      </refsect1>\n\n      <refsect1>\n\t<title>Examples</title>\n\t<para>Retrieve the current error string:</para>\n\t<programlisting>&egsess;\n...\nprintf(\"Error was: %s\\n\", ne_get_error(sess));</programlisting>\n\n\t<para>Set a new error string:</para>\n\t<programlisting>&egsess;\n...\nne_set_error(sess, \"Response missing header %s\", \"somestring\");</programlisting>\n      </refsect1>\n      \n    </refentry>\n"
  },
  {
    "path": "doc/ref/feat.xml",
    "content": "<refentry id=\"reffeat\">\n\n  <refmeta>\n    <refentrytitle>ne_has_support</refentrytitle>\n    <manvolnum>3</manvolnum>\n  </refmeta>\n\n  <refnamediv>\n    <refname id=\"ne_has_support\">ne_has_support</refname>\n    <refpurpose>determine feature support status</refpurpose>\n  </refnamediv>\n  \n  <refsynopsisdiv>\n\n    <funcsynopsis>\n\n      <funcsynopsisinfo>#include &lt;ne_utils.h&gt;</funcsynopsisinfo>\n\n      <funcprototype>\n        <funcdef>int <function>ne_has_support</function></funcdef>\n        <paramdef>int <parameter>feature</parameter></paramdef>\n      </funcprototype>\n\n    </funcsynopsis>\n\n  </refsynopsisdiv>\n\n  <refsect1>\n    <title>Description</title>\n\n    <para>The <function>ne_has_support</function> function can be used\n    to determine whether a particular optional feature, given by the\n    feature code <parameter>feature</parameter>, is supported.  The\n    following feature codes are available:\n\n    <variablelist>\n      <varlistentry>\n        <term><constant>NE_FEATURE_SSL</constant></term>\n        <listitem>\n          <simpara>Indicates support for SSL/TLS</simpara>\n        </listitem>\n      </varlistentry>\n      <varlistentry>\n        <term><constant>NE_FEATURE_ZLIB</constant></term>\n        <listitem>\n          <simpara>Indicates support for compressed responses</simpara>\n        </listitem>\n      </varlistentry>\n      <varlistentry>\n        <term><constant>NE_FEATURE_IPV6</constant></term>\n        <listitem>\n          <simpara>Indicates support for IPv6</simpara>\n        </listitem>\n      </varlistentry>\n      <varlistentry>\n        <term><constant>NE_FEATURE_LFS</constant></term>\n        <listitem>\n          <simpara>Indicates support for large files</simpara>\n        </listitem>\n      </varlistentry>\n      <varlistentry>\n        <term><constant>NE_FEATURE_SOCKS</constant></term>\n        <listitem>\n          <simpara>Indicates support for SOCKSv5</simpara>\n        </listitem>\n      </varlistentry>\n      <varlistentry>\n        <term><constant>NE_FEATURE_TS_SSL</constant></term>\n        <listitem>\n          <simpara>Indicates support for thread-safe SSL\n          initialization &mdash; see <xref linkend=\"ne_sock_init\"/></simpara>\n        </listitem>\n      </varlistentry>\n      <varlistentry>\n        <term><constant>NE_FEATURE_GSSAPI</constant></term>\n        <listitem>\n          <simpara>Indicates support for Negotiate authentication via GSSAPI</simpara>\n        </listitem>\n      </varlistentry>\n      <varlistentry>\n        <term><constant>NE_FEATURE_LIBPXY</constant></term>\n        <listitem>\n          <simpara>Indicates support for libproxy (in <xref linkend=\"ne_session_system_proxy\"/>)</simpara>\n        </listitem>\n      </varlistentry>\n      <varlistentry>\n        <term><constant>NE_FEATURE_NTLM</constant></term>\n        <listitem>\n          <simpara>Indicates support for NTLM authentication via Libntlm</simpara>\n        </listitem>\n      </varlistentry>\n    </variablelist>\n\n    </para>\n\n  </refsect1>\n\n  <refsect1>\n    <title>Return value</title>\n\n    <para><function>ne_has_support</function> returns non-zero if \n    the given feature is supported, or zero otherwise.</para>\n\n  </refsect1>\n\n  <refsect1>\n    <title>History</title>\n\n    <para>The <constant>NE_FEATURE_GSSAPI</constant> and\n    <constant>NE_FEATURE_LIBPXY</constant> constants are only\n    available in &neon; 0.34.0 and newer.</para>\n\n    <para>The <constant>NE_FEATURE_NTLM</constant> is only\n    available in &neon; 0.37.0 and newer.</para>\n  </refsect1>\n\n  <refsect1>\n    <title>See also</title>\n\n    <para><xref linkend=\"refvers\"/>, <xref linkend=\"refsockinit\"/></para>\n  </refsect1>\n\n</refentry>\n\n"
  },
  {
    "path": "doc/ref/getst.xml",
    "content": "    <refentry id=\"refgetst\">\n\n      <refmeta>\n\t<refentrytitle>ne_get_status</refentrytitle>\n\t<manvolnum>3</manvolnum>\n      </refmeta>\n\n      <refnamediv>\n\t<refname id=\"ne_get_status\">ne_get_status</refname>\n\t<refname id=\"ne_get_response_location\">ne_get_response_location</refname>\n\t<refname id=\"ne_get_response_retry_after\">ne_get_response_retry_after</refname>\n\t<refpurpose>retrieve HTTP response properties</refpurpose>\n      </refnamediv>\n      \n      <refsynopsisdiv>\n\t\n\t<funcsynopsis>\n\n\t  <funcsynopsisinfo>#include &lt;ne_request.h&gt;</funcsynopsisinfo>\n\n\t  <funcprototype>\n\t    <funcdef>const ne_status *<function>ne_get_status</function></funcdef>\n\t    <paramdef>const ne_request *<parameter>request</parameter></paramdef>\n\t  </funcprototype>\n\n\t  <funcprototype>\n\t    <funcdef>ne_uri *<function>ne_get_response_location</function></funcdef>\n\t    <paramdef>ne_request *<parameter>request</parameter></paramdef>\n\t  </funcprototype>\n\t  <funcprototype>\n\t    <funcdef>time_t <function>ne_get_response_retry_after</function></funcdef>\n\t    <paramdef>ne_request *<parameter>request</parameter></paramdef>\n\t  </funcprototype>\n\t</funcsynopsis>\n      </refsynopsisdiv>\n\n      <refsect1>\n\t<title>Description</title>\n\n\t<para>The <function>ne_get_status</function> function returns\na pointer to the HTTP status object giving the result of a request.\nThe object returned only becomes valid once the request has been\n<emphasis>successfully</emphasis> dispatched (the return value of\n<function>ne_request_dispatch</function> or\n<function>ne_begin_request</function> was zero).</para>\n\n<para>If the response includes a <literal>Location</literal> header,\nthe <function>ne_get_response_location</function> function parses and\nresolves the URI-reference relative to the request target. If a\nfragment (\"#fragment\") is applicable to the request target, it can be\npassed as an argument to allow appropriate relative resolution.</para>\n\n<para>The <function>ne_get_response_retry_after</function> function\nparses any <literal>Retry-After</literal> header included in the\nresponse. If the header value uses a relative time, it is interpreted\nrelative to the time the function was invoked, rather than the time\nthe response was received, so the function should be used directly\nafter dispatching the request.</para>\n      </refsect1>\n\n      <refsect1>\n\t<title>Return value</title>\n\n        <para><function>ne_get_status</function> returns a pointer to\n        the HTTP status object giving the result of a request. This\n        pointer is valid until the associated request object is\n        destroyed.</para>\n\n        <para><function>ne_get_response_location</function> returns a\n        malloc-allocated ne_uri object, or NULL if either the URI in\n        the Location header could not be parsed or the Location header\n        was not present.</para>\n\n        <para><function>ne_get_response_retry_after</function> returns\n        a time_t value, or zero if either no Retry-After header was\n        included or the header value could not be parsed.</para>\n      </refsect1>\n\n      <refsect1>\n\t<title>Examples</title>\n\t\n\t<para>Display the response status code of applying the\n<literal>HEAD</literal> method to some resource.</para>\n\n\t<programlisting>ne_request *req = ne_request_create(sess, \"HEAD\", \"/foo/bar\");\nif (ne_request_dispatch(req))\n   /* handle errors... */\nelse\n   printf(\"Response status code was %d\\n\", ne_get_status(req)->code);\nne_request_destroy(req);</programlisting>\n      </refsect1>\n\n      <refsect1>\n\t<title>History</title>\n\n        <para><function>ne_get_response_location</function> is\n        available in &neon; 0.34.0 and later.</para>\n      </refsect1>\n\n      <refsect1>\n\t<title>See also</title>\n\n\t<para><xref linkend=\"ne_status\"/>, <xref\n\tlinkend=\"ne_request_create\"/></para>\n      </refsect1>\n\n    </refentry>\n"
  },
  {
    "path": "doc/ref/hash.xml",
    "content": "    <refentry id=\"refhash\">\n\n      <refmeta>\n\t<refentrytitle>ne_strhash</refentrytitle>\n\t<manvolnum>3</manvolnum>\n      </refmeta>\n\n      <refnamediv>\n\t<refname id=\"ne_strhash\">ne_strhash</refname>\n\t<refname id=\"ne_vstrhash\">ne_vstrhash</refname>\n\t<refpurpose>string hash interface</refpurpose>\n      </refnamediv>\n      \n      <refsynopsisdiv>\n\n\t<funcsynopsis>\n          <funcsynopsisinfo>#include &lt;ne_string.h&gt;</funcsynopsisinfo>\n\n\t  <funcprototype>\n\t    <funcdef>char *<function>ne_strhash</function></funcdef>\n\t    <paramdef>unsigned int <parameter>flags</parameter></paramdef>\n\t    <paramdef><parameter>...</parameter></paramdef>\n\t  </funcprototype>\n\n\t  <funcprototype>\n\t    <funcdef>char *<function>ne_vstrhash</function></funcdef>\n\t    <paramdef>unsigned int <parameter>flags</parameter></paramdef>\n\t    <paramdef>va_list <parameter>ap</parameter></paramdef>\n\t  </funcprototype>\n        </funcsynopsis>\n\n      </refsynopsisdiv>\n\n      <refsect1>\n\t<title>Description</title>\n\n\t<para>The <function>ne_strhash</function> and\n\t<function>ne_vstrhash</function> functions can be used to\n\tcreate hashes.  The varargs argument list must be <type>const\n\tchar *</type> strings followed by a &null; terminator.  The\n\t<parameter>flags</parameter> argument must select exactly one\n\thash algorithm from the list below, which can be optionally\n\tbitwise-ORed with one of the formatting option.  The hash is\n\tcalculated for the concatenation of the argument list, without\n\tseparators.</para>\n\n        <refsect2>\n          <title>Hash algorithms</title>\n        \n        <para>The following hash algorithms are available:\n\t<variablelist>\n\t  <varlistentry>\n            <term><constant>NE_HASH_MD5</constant></term>\n\t    <listitem><simpara>MD5</simpara></listitem>\n\t  </varlistentry>\n\t  <varlistentry>\n            <term><constant>NE_HASH_SHA1</constant></term>\n\t    <listitem><simpara>SHA-1</simpara></listitem>\n\t  </varlistentry>\n\t  <varlistentry>\n            <term><constant>NE_HASH_SHA256</constant></term>\n\t    <listitem><simpara>SHA-256 (SHA-2)</simpara></listitem>\n\t  </varlistentry>\n\t  <varlistentry>\n            <term><constant>NE_HASH_SHA512</constant></term>\n\t    <listitem><simpara>SHA-512 (SHA-2)</simpara></listitem>\n\t  </varlistentry>\n\t  <varlistentry>\n            <term><constant>NE_HASH_SHA512_256</constant></term>\n\t    <listitem><simpara>SHA-512/256 (SHA-2)</simpara></listitem>\n\t  </varlistentry>\n        </variablelist>\n\n        </para></refsect2>\n        \n        <refsect2>\n          <title>Formatting options</title>\n          \n          <para>By default, the hash is returned as a hexadecimal\n          lower-case character string. The following formatting\n          options are available:\n        \n\t<variablelist>\n\t  <varlistentry>\n            <term><constant>NE_HASH_COLON</constant></term>\n\t    <listitem><simpara>colon-separated hex pairs, e.g. <literal>\"aa:11:22...\"</literal> </simpara></listitem>\n\t  </varlistentry>\n\t  <varlistentry>\n            <term><constant>NE_HASH_SPACE</constant></term>\n\t    <listitem><simpara>space-separated hex pairs, e.g. <literal>\"aa 11 22...\"</literal></simpara></listitem>\n\t  </varlistentry>\n          </variablelist></para>\n\n        </refsect2>\n        \n      </refsect1>\n\n      <refsect1>\n\t<title>Return value</title>\n\n        <para>The return value is the ASCII hexadecimal representation\n        of the hash as a malloc-allocated, NUL-terminated string, or\n        &null; if the hash cannot be created.  The string length is\n        determined by the hash algorithm (and formatting options\n        used).  Support for hash algorithms is specific to the SSL\n        toolkit with which &neon; is compiled.  Some systems will\n        further restrict hash availability at runtime, e.g. due to\n        FIPS mode.</para>\n\n      </refsect1>\n\n      <refsect1>\n\t<title>History</title>\n\n        <para><function>ne_strhash</function> and <function>ne_vstrhash</function> are\n        available in &neon; 0.32.0 and later.</para>\n\n        <para>The <constant>NE_HASH_SHA1</constant> flag is available in\n        &neon; 0.37.0 and later.</para>\n      </refsect1>\n    </refentry>\n"
  },
  {
    "path": "doc/ref/i18n.xml",
    "content": "<refentry id=\"refi18n\">\n\n  <refmeta>\n    <refentrytitle>ne_i18n_init</refentrytitle>\n    <manvolnum>3</manvolnum>\n  </refmeta>\n\n  <refnamediv>\n    <refname id=\"ne_i18n_init\">ne_i18n_init</refname>\n    <refpurpose>functions to initialize internationalization support</refpurpose>\n  </refnamediv>\n  \n  <refsynopsisdiv>\n\n    <funcsynopsis>\n\n      <funcsynopsisinfo>#include &lt;ne_i18n.h&gt;</funcsynopsisinfo>\n\n      <funcprototype>\n        <funcdef>void <function>ne_i18n_init</function></funcdef>\n        <paramdef>const char *<parameter>encoding</parameter></paramdef>\n      </funcprototype>\n\n    </funcsynopsis>\n\n  </refsynopsisdiv>\n\n  <refsect1>\n    <title>Description</title>\n\n    <para>The <function>ne_i18n_init</function> function can be used\n    to enable support for translated messages in the &neon; library.\n    The <parameter>encoding</parameter> parameter, if non-&null;,\n    specifies the character encoding required for generated translated\n    string.  If it is &null;, the appropriate character encoding for\n    the process locale will be used.</para>\n\n    <para>This call is only strictly necessary if either:\n\n    <orderedlist numeration=\"loweralpha\">\n        \n      <listitem><simpara>&neon; has been installed into a different\n      prefix than the <literal>gettext</literal> implementation on\n      which it depends for i18n purposes, or</simpara></listitem>\n\n      <listitem><simpara>the caller requires that translated messages\n      are in a particular character encoding.</simpara></listitem>\n\n    </orderedlist></para>\n\n    <para>If <function>ne_i18n_init</function> is never called, the\n    message catalogs will not be found if case (a) applies (and so\n    English error messages will be used), and will use the default\n    character encoding specified by the process locale.  The library\n    will otherwise operate correctly.</para>\n\n    <para>Note that the encoding used is a process-global setting and\n    so results may be unexpected if other users of &neon; within the\n    process call <function>ne_i18n_init</function> with a different\n    encoding parameter.</para>\n\n  </refsect1>\n\n  <refsect1>\n    <title>See also</title>\n\n    <para><xref linkend=\"ne_sock_init\"/></para>\n  </refsect1>\n\n</refentry>\n\n"
  },
  {
    "path": "doc/ref/iaddr.xml",
    "content": "<refentry id=\"refiaddr\">\n\n  <refmeta>\n    <refentrytitle>ne_iaddr_make</refentrytitle>\n    <manvolnum>3</manvolnum>\n  </refmeta>\n\n  <refnamediv>\n    <refname id=\"ne_iaddr_make\">ne_iaddr_make</refname>\n    <refname id=\"ne_iaddr_cmp\">ne_iaddr_cmp</refname>\n    <refname id=\"ne_iaddr_print\">ne_iaddr_print</refname>\n    <refname id=\"ne_iaddr_typeof\">ne_iaddr_typeof</refname>\n    <refname id=\"ne_iaddr_parse\">ne_iaddr_parse</refname>\n    <refname id=\"ne_iaddr_raw\">ne_iaddr_raw</refname>\n    <refname id=\"ne_iaddr_put\">ne_iaddr_put</refname>\n    <refname id=\"ne_iaddr_reverse\">ne_iaddr_reverse</refname>\n    <refname id=\"ne_iaddr_free\">ne_iaddr_free</refname>\n    <refpurpose>functions to manipulate network addresses</refpurpose>\n  </refnamediv>\n  \n  <refsynopsisdiv>\n\n    <funcsynopsis>\n\n      <funcsynopsisinfo>#include &lt;ne_socket.h&gt;\n\ntypedef enum {\n    ne_iaddr_ipv4 = 0,\n    ne_iaddr_ipv6\n} <type>ne_iaddr_type</type>;</funcsynopsisinfo>\n\n      <funcprototype>\n        <funcdef>ne_inet_addr *<function>ne_iaddr_make</function></funcdef>\n        <paramdef>ne_iaddr_type <parameter>type</parameter></paramdef>\n        <paramdef>const unsigned char *<parameter>raw</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>int <function>ne_iaddr_cmp</function></funcdef>\n        <paramdef>const ne_inet_addr *<parameter>ia1</parameter></paramdef>\n        <paramdef>const ne_inet_addr *<parameter>ia2</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>char *<function>ne_iaddr_print</function></funcdef>\n        <paramdef>const ne_inet_addr *<parameter>ia</parameter></paramdef>\n        <paramdef>char *<parameter>buffer</parameter></paramdef>\n        <paramdef>size_t <parameter>bufsiz</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>ne_iaddr_type <function>ne_iaddr_typeof</function></funcdef>\n        <paramdef>const ne_inet_addr *<parameter>ia</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>ne_inet_addr *<function>ne_iaddr_parse</function></funcdef>\n        <paramdef>const char *<parameter>address</parameter></paramdef>\n        <paramdef>ne_iaddr_type <parameter>type</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>unsigned char *<function>ne_iaddr_raw</function></funcdef>\n        <paramdef>const ne_inet_addr *<parameter>ia</parameter></paramdef>\n        <paramdef>unsigned char *<parameter>buffer</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>ne_inet_addr *<function>ne_iaddr_put</function></funcdef>\n        <paramdef>ne_inet_addr *<parameter>ia</parameter></paramdef>\n        <paramdef>ne_iaddr_type <parameter>type</parameter></paramdef>\n        <paramdef>const unsigned char *<parameter>raw</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>int <function>ne_iaddr_reverse</function></funcdef>\n        <paramdef>const ne_inet_addr *<parameter>ia</parameter></paramdef>\n        <paramdef>char *<parameter>buffer</parameter></paramdef>\n        <paramdef>size_t <parameter>buflen</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>void <function>ne_iaddr_free</function></funcdef>\n        <paramdef>ne_inet_addr *<parameter>ia</parameter></paramdef>\n      </funcprototype>\n\n    </funcsynopsis>\n\n  </refsynopsisdiv>\n\n  <refsect1>\n    <title>Description</title>\n\n    <para><function>ne_iaddr_make</function> creates an\n    <type>ne_inet_addr</type> object from a raw binary network\n    address; for instance the four bytes <literal>0x7f 0x00 0x00\n    0x01</literal> represent the IPv4 address\n    <literal>127.0.0.1</literal>.  The object returned is suitable for\n    passing to <function>ne_sock_connect</function>.  A binary IPv4\n    address contains four bytes; a binary IPv6 address contains\n    sixteen bytes; addresses passed must be in network byte\n    order.</para>\n\n    <para><function>ne_iaddr_cmp</function> compares two network\n    address objects; returning zero only if they are identical.  The\n    objects need not have the same address type; if the addresses are\n    not of the same type, the return value is guaranteed to be\n    non-zero.</para>\n\n    <para><function>ne_iaddr_print</function> prints a human-readable\n    string representation of a network address into a buffer, for\n    instance the string <literal>\"127.0.0.1\"</literal>.</para>\n\n    <para><function>ne_iaddr_typeof</function> returns the type of the\n    given network address object.</para>\n\n    <para><function>ne_iaddr_put</function> changes an existing\n    network address object to a new raw byte representation given by\n    parameter <parameter>type</parameter> (which can be different to\n    the current type of the object). The raw data must be of\n    length 4 bytes for an IPv4 address, or 16 bytes for an IPv6\n    address.</para>\n\n    <para><function>ne_iaddr_parse</function> parses a string\n    representation of a network address (such as\n    <literal>\"127.0.0.1\"</literal> and creates a network address\n    object to represent the parsed address.</para>\n\n    <para><function>ne_iaddr_raw</function> writes the raw byte\n    representation of a network address to the provided buffer.  The\n    bytes are written in network byte order; the buffer must be of\n    suitable length for the type of address (4 bytes for an IPv4\n    address, 16 bytes for an IPv6 address).</para>\n\n    <para><function>ne_iaddr_reverse</function> performs a reverse\n    name lookup on the address object, writing the (first) hostname\n    associated with the IP address to the provided buffer.  If the\n    hostname is longer than the buffer it will be silently truncated;\n    on success the string written to the buffer is always\n    &nul;-terminated.</para>\n\n    <para><function>ne_iaddr_free</function> releases the memory\n    associated with a network address object.</para>\n\n  </refsect1>\n\n  <refsect1>\n    <title>Return value</title>\n\n    <para><function>ne_iaddr_make</function> returns &null; if the\n    address type passed is not supported (for instance on a platform\n    which does not support IPv6).</para>\n\n    <para><function>ne_iaddr_print</function> returns the\n    <parameter>buffer</parameter> pointer, and never &null;.</para>\n\n    <para><function>ne_iaddr_parse</function> returns a network\n    address object on success, or &null; on failure to parse the\n    <parameter>address</parameter> parameter.</para>\n\n    <para><function>ne_iaddr_reverse</function> returns zero on\n    success or non-zero if no hostname is associated with the\n    address.</para>\n\n    <para><function>ne_iaddr_raw</function> returns the\n    <parameter>buffer</parameter> parameter, and never &null;.</para>\n\n    <para><function>ne_iaddr_put</function> returns the passed in\n    <parameter>ia</parameter> parameter, or &null; if the address type\n    passed is not supported (for instance on a platform which does not\n    support IPv6).</para>\n\n  </refsect1>\n\n  <refsect1>\n    <title>Examples</title>\n\n    <para>The following example connects a socket to port 80 at the\n    address <literal>127.0.0.1</literal>.</para>\n \n    <programlisting>unsigned char addr[] = \"\\0x7f\\0x00\\0x00\\0x01\";\nne_inet_addr *ia;\n\nia = ne_iaddr_make(ne_iaddr_ipv4, addr);\nif (ia != NULL) {\n    ne_socket *sock = ne_sock_connect(ia, 80);\n    ne_iaddr_free(ia);\n    /* ... */\n} else {\n    /* ... */\n}</programlisting>\n\n  </refsect1>\n\n  <refsect1>\n    <title>History</title>\n\n    <para>The <function>ne_iaddr_raw</function> function is available\n    in &neon; 0.29.0 and later.</para>\n\n    <para>The <function>ne_iaddr_put</function> function is available\n    in &neon; 0.37.0 and later.</para>\n\n  </refsect1>\n\n  <refsect1>\n    <title>See also</title>\n\n    <para><xref linkend=\"ne_addr_resolve\"/></para>\n  </refsect1>\n\n</refentry>\n\n"
  },
  {
    "path": "doc/ref/init.xml",
    "content": "<refentry id=\"refsockinit\">\n\n  <refmeta>\n    <refentrytitle>ne_sock_init</refentrytitle>\n    <manvolnum>3</manvolnum>\n  </refmeta>\n\n  <refnamediv>\n    <refname id=\"ne_sock_init\">ne_sock_init</refname>\n    <refname id=\"ne_sock_exit\">ne_sock_exit</refname>\n    <refpurpose>perform library initialization</refpurpose>\n  </refnamediv>\n  \n  <refsynopsisdiv>\n\n    <funcsynopsis>\n\n      <funcsynopsisinfo>#include &lt;ne_socket.h&gt;</funcsynopsisinfo>\n\n      <funcprototype>\n        <funcdef>int <function>ne_sock_init</function></funcdef>\n\t<void/>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>void <function>ne_sock_exit</function></funcdef>\n\t<void/>\n      </funcprototype>\n\n    </funcsynopsis>\n\n  </refsynopsisdiv>\n\n  <refsect1>\n    <title>Description</title>\n\n    <para>In some platforms and configurations, &neon; may be using\n    some socket or SSL libraries which require global initialization\n    before use.  To perform this initialization, the\n    <function>ne_sock_init</function> function must be called before\n    any other library functions are used.</para>\n\n    <para>Once all use of &neon; is complete,\n    <function>ne_sock_exit</function> can be called to perform\n    de-initialization of socket or SSL libraries, if necessary.  Uses\n    of <function>ne_sock_init</function> and\n    <function>ne_sock_exit</function> are \"reference counted\"; if N\n    calls to <function>ne_sock_init</function> are made, only the Nth\n    call to <function>ne_sock_exit</function> will have effect.</para>\n\n    <para><function>ne_sock_init</function> will set the disposition\n    of the <literal>SIGPIPE</literal> signal to\n    <emphasis>ignored</emphasis>.  No change is made to the\n    <literal>SIGPIPE</literal> disposition by\n    <function>ne_sock_exit</function>.</para>\n\n    <para>Both the SSL libraries supported by &neon; &mdash; OpenSSL\n    and GnuTLS &mdash; require callbacks to be registered to allow\n    thread-safe use of SSL.  These callbacks are stored as global\n    variables and so their state persists for as long as the library\n    in question is loaded into the process.  If multiple users of the\n    SSL library exist within the process, this can be problematic,\n    particularly if one is dynamically loaded (and may subsequently be\n    unloaded).</para>\n\n    <para>If &neon; is configured using the\n    <literal>--enable-threadsafe-ssl</literal> flag, thread-safe SSL\n    support will be enabled automatically, as covered in the following\n    section.  Otherwise, it is not safe to use &neon; with SSL in a\n    multi-threaded process.  The <xref linkend=\"ne_has_support\"/>\n    function can be used to determine whether &neon; is built to\n    enable thread-safety support in the SSL library.</para>\n    \n    <refsect2>\n      <title>Thread-safe SSL with OpenSSL</title>\n\n      <para>&neon; follows two simple rules when dealing with the\n      OpenSSL locking callbacks:\n\n      <itemizedlist>\n        \n        <listitem><simpara><function>ne_sock_init</function> will set\n        thread-safety locking callbacks if and only if no locking\n        callbacks are already registered.</simpara></listitem>\n        \n        <listitem><simpara><function>ne_sock_exit</function> will\n        unset the thread-safety locking callbacks if and only if the\n        locking callbacks registered are those registered by\n        <function>ne_sock_init</function>.</simpara></listitem>\n\n      </itemizedlist>\n\n      Applications and libraries should be able to co-operate to\n      ensure that SSL use is always thread-safe if similar rules are\n      always followed.</para>\n\n    </refsect2>\n\n    <refsect2>\n      <title>Thread-safe SSL with GnuTLS</title>\n\n      <para>The cryptography library used by GnuTLS, libgcrypt, only\n      supports an initialization operation to register thread-safety\n      callbacks.  <function>ne_sock_init</function> will register the\n      thread-safe locking callbacks on first use;\n      <function>ne_sock_exit</function> cannot unregister them.  If\n      multiple users of GnuTLS are present within the process, it is\n      unsafe to dynamically unload &neon; from the process if &neon;\n      is configured with thread-safe SSL support enabled (since the\n      callbacks would be left pointing at unmapped memory once &neon;\n      is unloaded).</para>\n\n    </refsect2>\n\n  </refsect1>\n\n  <refsect1>\n    <title>Return value</title>\n\n    <para><function>ne_sock_init</function> returns zero on success,\n    or non-zero on error.  If an error occurs, no further use of the\n    &neon; library should be attempted.</para>\n\n  </refsect1>\n\n  <refsect1>\n    <title>See also</title>\n\n    <para><xref linkend=\"refneon\"/>, <xref linkend=\"reffeat\"/></para>\n  </refsect1>\n\n</refentry>\n"
  },
  {
    "path": "doc/ref/lower.xml",
    "content": "<refentry id=\"reflower\">\n\n  <refmeta>\n    <refentrytitle>ne_strlower</refentrytitle>\n    <manvolnum>3</manvolnum>\n  </refmeta>\n\n  <refnamediv>\n    <refname id=\"ne_strlower\">ne_strlower</refname>\n    <refname id=\"ne_tolower\">ne_tolower</refname>\n    <refname id=\"ne_tolower_array\">ne_tolower_array</refname>\n    <refpurpose>convert string or characters to lower-case</refpurpose>\n  </refnamediv>\n  \n  <refsynopsisdiv>\n\n    <funcsynopsis>\n\n      <funcsynopsisinfo>#include &lt;ne_string.h&gt;\n\nconst unsigned char *ne_tolower_array(void);\n#define ne_tolower(c) (...)</funcsynopsisinfo>\n\n      <funcprototype>\n        <funcdef>char *<function>ne_strlower</function></funcdef>\n        <paramdef>char *<parameter>str</parameter></paramdef>\n      </funcprototype>\n\n    </funcsynopsis>\n    \n  </refsynopsisdiv>\n\n  <refsect1>\n    <title>Description</title>\n\n    <para>The <function>ne_strlower</function> function modifies every\n    character in the <parameter>str</parameter> parameter to\n    lower-case equivalent in-place, and returns\n    <parameter>str</parameter>.</para>\n\n    <para>The <function>ne_tolower</function> macro returns a\n    lower-case equivalent of <type>char</type>\n    <parameter>c</parameter>. The\n    <function>ne_tolower_array</function> returns a character mapping\n    table which is an implementation detail of this macro.</para>\n\n    <para>All the above operate on ASCII characters, independent of\n    the locale.</para>\n  </refsect1>\n\n  <refsect1>\n    <title>Return value</title>\n\n    <para><function>ne_strlower</function> returns the\n    <parameter>str</parameter> parameter.</para>\n\n  </refsect1>\n\n  <refsect1>\n    <title>History</title>\n\n    <para>The <function>ne_strlower</function> function is available in &neon; 0.37.0 and later.</para>\n\n  </refsect1>\n\n  <refsect1>\n    <title>See also</title>\n\n    <para><xref linkend=\"ne_strdup\"/></para>\n  </refsect1>\n\n</refentry>\n"
  },
  {
    "path": "doc/ref/neon.xml",
    "content": "<refentry id=\"refneon\">\n\n  <refmeta>\n    <refentrytitle>neon</refentrytitle>\n    <manvolnum>3</manvolnum>\n  </refmeta>\n\n  <refnamediv>\n    <refname>neon</refname>\n    <refpurpose>HTTP and WebDAV client library</refpurpose>\n  </refnamediv>\n\n  <refsect1>\n    <title>Description</title>\n\n    <para>neon is an HTTP and WebDAV client library.  The major\n    abstractions exposed are the HTTP <emphasis>session</emphasis>,\n    created by <xref linkend=\"ne_session_create\"/>; and the HTTP\n    <emphasis>request</emphasis>, created by <xref\n    linkend=\"ne_request_create\"/>.  HTTP authentication is handled\n    transparently for server and proxy servers, see <xref\n    linkend=\"ne_set_server_auth\"/>; complete SSL/TLS support is also\n    included, see <xref linkend=\"ne_ssl_set_verify\"/>.</para>\n\n  </refsect1>\n\n  <refsect1>\n    <title>Conventions</title>\n\n    <para>Some conventions are used throughout the neon API, to\n    provide a consistent and simple interface; these are documented\n    below.</para>\n\n  <refsect2>\n    <title>Thread-safeness and global initialization</title>\n\n    <para>&neon; itself is implemented to be thread-safe (avoiding any\n    use of global state), but relies on the operating system providing\n    a thread-safe resolver interface.  Modern operating systems offer\n    the thread-safe <function>getaddrinfo</function> interface, which\n    &neon; supports; some others implement\n    <function>gethostbyname</function> using thread-local\n    storage.</para>\n\n    <para>To allow thread-safe use of SSL in the OpenSSL and GnuTLS\n    libraries &neon; must be configured using the\n    <literal>--enable-threadsafe-ssl</literal>; if this is done,\n    locking callbacks will be registered by <xref\n    linkend=\"ne_sock_init\"/>; note that care must be exercised if\n    &neon; is used in conjunction with another library which uses\n    OpenSSL or GnuTLS.</para>\n\n    <para>Some platforms and libraries used by &neon; require global\n    initialization before use; notably:\n\n    <itemizedlist>\n      <listitem><simpara>The <literal>SIGPIPE</literal> signal\n      disposition must be set to <emphasis>ignored</emphasis> or\n      otherwise handled to avoid process termination when writing to a\n      socket which has been shutdown by the peer.</simpara></listitem>\n\n      <listitem><simpara>OpenSSL and GnuTLS require global\n      initialization to load shared lookup\n      tables.</simpara></listitem>\n\n      <listitem><simpara>The Win32 socket library requires\n      initialization before use.</simpara></listitem>\n    </itemizedlist>\n\n    The <xref linkend=\"ne_sock_init\"/> function should be called\n    before any other use of &neon; to perform any necessary\n    initialization needed for the particular platform.  Applications\n    wishing to perform all the necessary process-global initialization\n    steps themselves may omit to call <xref linkend=\"ne_sock_init\"/>\n    (and <xref linkend=\"ne_sock_exit\"/>); &neon; neither checks whether\n    these functions are called nor calls them itself.</para>\n\n    <para>For some applications and configurations it may be necessary\n    to call <xref linkend=\"ne_i18n_init\"/> to initialize the support\n    for internationalization in &neon;.</para>\n\n  </refsect2>\n\n  <refsect2>\n    <title>Asynchronous signal safety</title>\n    \n    <para>No function in &neon; is defined to be <quote>async-signal safe</quote> -\n    that is, no function is safe to call from a signal handler.  Any\n    call into the &neon; library from a signal handler will have\n    undefined behaviour - in other words, it may crash the\n    process.</para>\n  </refsect2>\n\n  <refsect2>\n    <title>Functions using global state</title>\n\n    <para>Any function in &neon; may modify the\n    <literal>errno</literal> global variable as a side-effect.  Except\n    where explicitly documented, the value of <literal>errno</literal>\n    is unspecified after any &neon; function call.</para>\n\n    <para>Other than in the use of <literal>errno</literal>, the only\n    functions which use or modify process-global state in &neon; are\n    as follows:\n\n    <itemizedlist>\n      <listitem><simpara><xref linkend=\"ne_sock_init\"/>, <xref\n      linkend=\"ne_i18n_init\"/>, and <xref linkend=\"ne_sock_exit\"/>, as\n      described above</simpara></listitem>\n\n      <listitem><simpara><function>ne_debug_init</function> and\n      <function>ne_debug</function>, if enabled at compile time; for\n      debugging output</simpara></listitem>\n\n      <listitem><simpara><xref linkend=\"ne_oom_callback\"/> for\n      installing a process-global callback to be invoked on\n      <function>malloc</function> failure</simpara></listitem>\n\n    </itemizedlist></para>\n\n  </refsect2>      \n\n  <refsect2>\n    <title>Namespaces</title>\n\n    <para>To avoid possible collisions between names used for symbols\n    and preprocessor macros by an application and the libraries it\n    uses, it is good practice for each library to reserve a particular\n    <emphasis>namespace prefix</emphasis>.  An application which\n    ensures it uses no names with these prefixes is then guaranteed to\n    avoid such collisions.</para>\n\n    <para>The &neon; library reserves the use of the namespace\n    prefixes <literal>ne_</literal> and <literal>NE_</literal>.  The\n    libraries used by &neon; may also reserve certain namespaces;\n    collisions between these libraries and a &neon;-based application\n    will not be detected at compile time, since the underlying library\n    interfaces are not exposed through the &neon; header files.  Such\n    collisions can only be detected at link time, when the linker\n    attempts to resolve symbols.  The following list documents some of\n    the namespaces claimed by libraries used by &neon;; this list may\n    be incomplete.</para>\n\n    <variablelist>\n\n      <varlistentry>\n\t<term>SSL, ssl, TLS, tls, ERR_, BIO_, d2i_, i2d_, ASN1_</term>\n\t<listitem><simpara>Some of the many prefixes used by the OpenSSL\n\tlibrary; little attempt has been made to keep exported symbols\n\twithin any particular prefixes for this\n\tlibrary.</simpara></listitem>\n      </varlistentry>\n\n      <varlistentry>\n        <term>gnutls_, gcry_, gpg_</term>\n        <listitem><simpara>Namespaces used by the GnuTLS library (and\n        dependencies thereof)</simpara></listitem>\n      </varlistentry>\n\n      <varlistentry>\n\t<term>XML_, Xml[A-Z]</term> <listitem><simpara>Namespaces\n\tused by the expat library.</simpara></listitem>\n      </varlistentry>\n\n      <varlistentry>\n\t<term>xml[A-Z], html[A-Z], docb[A-Z]</term>\n\t<listitem><simpara>Namespaces used by the libxml2 library; a\n\trelatively small number of symbols are used without these\n\tprefixes.</simpara></listitem>\n      </varlistentry>\n\n      <varlistentry>\n        <term>inflate, deflate, crc32, compress, uncompress, adler32,\n        zlib</term>\n\t<listitem><simpara>Namespaces used by the zlib library; a\n\trelatively small number of symbols are used without these\n\tprefixes.</simpara></listitem>\n      </varlistentry>\n\n      <varlistentry>\n        <term>krb5, gss, GSS, asn1, decode_krb5, encode_krb5, profile,\n        mit</term>\n\n        <listitem><simpara>Some of the prefixes used by the MIT GSSAPI\n        library and dependencies thereof; a number of symbols lie\n        outside these prefixes.</simpara></listitem>\n      </varlistentry>\n\n      <varlistentry>\n        <term>pakchois_</term>\n        <listitem><simpara>Namespace used by the pakchois \n         library.</simpara></listitem>\n      </varlistentry>\n\n      <varlistentry>\n        <term>px_</term>\n        <listitem><simpara>Namespace used by the libproxy\n         library.</simpara></listitem>\n      </varlistentry>\n\n    </variablelist>\n\n  </refsect2>\n\n  <refsect2>\n    <title>Argument validation</title>\n  \n    <para>&neon; does not attempt to validate that the parameters\n    passed to functions conform to the API (for instance, checking\n    that pointer arguments are not &null;).  Any use of the &neon; API\n    which is not documented to produce a certain behaviour results is\n    said to produce <emphasis>undefined behaviour</emphasis>; it is\n    likely that &neon; will segfault under these conditions.</para>\n\n  </refsect2>\n\n  <refsect2>\n    <title>URI paths, WebDAV metadata</title>\n\n    <para>The path strings passed to any function must be\n    <emphasis>URI-encoded</emphasis> by the application; &neon; never\n    performs any URI encoding or decoding internally.  WebDAV property\n    names and values must be valid UTF-8 encoded Unicode\n    strings.</para>\n\n  </refsect2>\n\n  <refsect2>\n    <title>User interaction</title>\n\n    <para>As a pure library interface, &neon; will never produce\n    output on <constant>stdout</constant> or\n    <constant>stderr</constant>; all user interaction is the\n    responsibility of the application.</para>\n  </refsect2>\n\n  <refsect2>\n    <title>Memory handling</title>\n\n    <para>neon does not attempt to cope gracefully with an\n    out-of-memory situation; instead, by default, the\n    <function>abort</function> function is called to immediately\n    terminate the process.  An application may register a custom\n    function which will be called before <function>abort</function> in\n    such a situation; see <xref linkend=\"ne_oom_callback\"/>.</para>\n  \n  </refsect2>\n\n  <refsect2>\n    <title>Callbacks and userdata</title>\n\n    <para>Whenever a callback is registered, a\n    <literal>userdata</literal> pointer is also used to allow the\n    application to associate a context with the callback.  The\n    userdata is of type <type>void *</type>, allowing any pointer to\n    be used.</para>\n\n  </refsect2>\n\n  <refsect2>\n    <title>Large File Support</title>\n\n    <para>Since version 0.27.0, &neon; transparently uses the \"LFS\n    transitional\" interfaces in functions which use file descriptors.\n    This allows use of files larger than 2GiB on platforms with a\n    native 32-bit <literal>off_t</literal> type, where LFS support is\n    available.</para>\n\n    <para>Some &neon; interfaces use the <literal>ne_off_t</literal>\n    type, which is defined to be either <literal>off_t</literal> or\n    <literal>off64_t</literal> according to whether LFS support is\n    detected at build time.  &neon; does not use or require the\n    <literal>-D_FILE_OFFSET_BITS=64</literal> macro definition.</para>\n\n  </refsect2>\n\n  </refsect1>\n\n  <refsect1>\n    <title>See also</title>\n\n    <para><xref linkend=\"refsess\"/>, <xref linkend=\"ne_oom_callback\"/>,\n    <ulink url=\"https://notroj.github.io/neon/\"/></para>\n  </refsect1>\n\n</refentry>\n\n"
  },
  {
    "path": "doc/ref/nonce.xml",
    "content": "<refentry id=\"ne_mknonce\">\n\n  <refmeta>\n    <refentrytitle>ne_mknonce</refentrytitle>\n    <manvolnum>3</manvolnum>\n  </refmeta>\n\n  <refnamediv>\n    <refname>ne_mknonce</refname>\n    <refpurpose>generate a nonce</refpurpose>\n  </refnamediv>\n\n  <refsynopsisdiv>\n    <funcsynopsis>\n      <funcsynopsisinfo>#include &lt;ne_string.h&gt;</funcsynopsisinfo>\n      <funcprototype>\n        <funcdef>int <function>ne_mknonce</function></funcdef>\n        <paramdef>unsigned char *<parameter>nonce</parameter></paramdef>\n        <paramdef>size_t <parameter>len</parameter></paramdef>\n        <paramdef>unsigned int <parameter>flags</parameter></paramdef>\n      </funcprototype>\n    </funcsynopsis>\n  </refsynopsisdiv>\n\n  <refsect1>\n    <title>Description</title>\n\n    <para><function>ne_mknonce</function> fills the buffer pointed to\n    by <parameter>nonce</parameter> with <parameter>len</parameter>\n    bytes of random data suitable for use as a nonce.  The value of\n    <parameter>len</parameter> must be greater than zero and no\n    greater than 256.</para>\n\n    <para>The <parameter>flags</parameter> parameter is reserved for\n    future use and must be set to zero.</para>\n\n    <para>The caller is responsible for ensuring that the buffer\n    pointed to by <parameter>nonce</parameter> is at least\n    <parameter>len</parameter> bytes in size.</para>\n  </refsect1>\n\n  <refsect1>\n    <title>Return value</title>\n\n    <para><function>ne_mknonce</function> returns zero on success.  On\n    error, a non-zero <type>errno</type> value is returned indicating\n    the cause of the failure; the buffer contents are\n    undefined.</para>\n  </refsect1>\n\n\n  <refsect1>\n    <title>Example</title>\n\n    <para>The following example generates a 16-byte nonce and encodes\n    it as a hexadecimal string.</para>\n\n    <programlisting>unsigned char buf[16];\nunsigned char hex[33];\nint i, err;\n\nerr = ne_mknonce(buf, sizeof buf, 0);\nif (err) {\n    fprintf(stderr, \"ne_mknonce failed: %s\\n\", strerror(err));\n    return -1;\n}\n\nfor (i = 0; i &lt; 16; i++)\n    sprintf(hex + 2 * i, \"%02x\", buf[i]);\nhex[32] = '\\0';</programlisting>\n  </refsect1>\n\n  <refsect1>\n    <title>History</title>\n\n    <para><function>ne_mknonce</function> is available in &neon;\n    0.37.0 and later.</para>\n  </refsect1>\n\n</refentry>\n"
  },
  {
    "path": "doc/ref/opts.xml",
    "content": "    <refentry id=\"refopts\">\n\n      <refmeta>\n\t<refentrytitle>ne_set_useragent</refentrytitle>\n\t<manvolnum>3</manvolnum>\n      </refmeta>\n\n      <refnamediv>\n\t<refname id=\"ne_set_useragent\">ne_set_useragent</refname>\n\t<refname id=\"ne_set_read_timeout\">ne_set_read_timeout</refname>\n\t<refname id=\"ne_set_connect_timeout\">ne_set_connect_timeout</refname>\n\t<refname id=\"ne_get_scheme\">ne_get_scheme</refname>\n\t<refname id=\"ne_get_server_hostport\">ne_get_server_hostport</refname>\n\t<refpurpose>common properties for HTTP sessions</refpurpose>\n      </refnamediv>\n      \n      <refsynopsisdiv>\n\t\n\t<funcsynopsis>\n\n\t  <funcsynopsisinfo>#include &lt;ne_session.h&gt;</funcsynopsisinfo>\n\n\t  <funcprototype>\n\t    <funcdef>void <function>ne_set_useragent</function></funcdef>\n\t    <paramdef>ne_session *<parameter>session</parameter></paramdef>\n\t    <paramdef>const char *<parameter>product</parameter></paramdef>\n\t  </funcprototype>\n\n\t  <funcprototype>\n\t    <funcdef>void <function>ne_set_read_timeout</function></funcdef>\n\t    <paramdef>ne_session *<parameter>session</parameter></paramdef>\n\t    <paramdef>int <parameter>timeout</parameter></paramdef>\n\t  </funcprototype>\n\n\t  <funcprototype>\n\t    <funcdef>void <function>ne_set_connect_timeout</function></funcdef>\n\t    <paramdef>ne_session *<parameter>session</parameter></paramdef>\n\t    <paramdef>int <parameter>timeout</parameter></paramdef>\n\t  </funcprototype>\n\n\t  <funcprototype>\n\t    <funcdef>const char *<function>ne_get_scheme</function></funcdef>\n\t    <paramdef>ne_sesssion *<parameter>session</parameter></paramdef>\n\t  </funcprototype>\n\n\t  <funcprototype>\n\t    <funcdef>const char *<function>ne_get_server_hostport</function></funcdef>\n\t    <paramdef>ne_sesssion *<parameter>session</parameter></paramdef>\n\t  </funcprototype>\n\n\t</funcsynopsis>\n\t\n      </refsynopsisdiv>\n\n      <refsect1>\n\t<title>Description</title>\n\t\n\t<para>The <literal>User-Agent</literal> request header is used\nto identify the software which generated the request for statistical\nor debugging purposes.  neon does not send a\n<literal>User-Agent</literal> header unless a call is made to the\n<function>ne_set_useragent</function>.\n<function>ne_set_useragent</function> must be passed a product string\nconforming to RFC2616's product token grammar; of the form\n<literal>\"Product/Version\"</literal>.</para>\n\n\t<para>When neon reads from a socket, by default the read\noperation will time out after 60 seconds, and the request will fail\ngiving an <errorcode>NE_TIMEOUT</errorcode> error.  To configure this\ntimeout interval, call <function>ne_set_read_timeout</function> giving\nthe desired number of seconds as the <parameter>timeout</parameter>\nparameter.</para>\n\n\t<para>When a connection is being established to a server,\n\tnormally only the system's TCP timeout handling will apply.\n\tTo configure a specific (and probably shorter) timeout, the\n\t<function>ne_set_connect_timeout</function> can be used,\n\tgiving the desired number of seconds as the\n\t<parameter>timeout</parameter> parameter.  If\n\t<literal>0</literal> is passed, then the default behaviour of\n\tusing the system TCP timeout will be used.</para>\n\n         <para>The scheme used to initially create the session will be\n         returned by <function>ne_get_scheme</function>.</para>\n\n         <para>The hostport pair with which the session is associated\n         will be returned by the\n         <function>ne_get_server_hostport</function>; for example\n         <literal>www.example.com:8080</literal>.  Note that the\n         <literal>:port</literal> will be omitted if the default port\n         for the scheme is used.</para>\n\n      </refsect1>      \n\n      <refsect1>\n\t<title>Examples</title>\n\t<para>Set a user-agent string:</para>\n\t<programlisting>&egsess;\nne_set_useragent(sess, \"MyApplication/2.1\");</programlisting>\n\n\t<para>Set a 30 second read timeout:</para>\n\t<programlisting>&egsess;\nne_set_read_timeout(sess, 30);</programlisting>\n\n      </refsect1>\n\n      <refsect1>\n\t<title>See also</title>\n\t\n\t<para><xref linkend=\"ne_session_create\"/>, <xref\n\tlinkend=\"ne_set_session_flag\"/>.</para>\n      </refsect1>\n\n    </refentry>\n"
  },
  {
    "path": "doc/ref/param.xml",
    "content": "    <refentry id=\"refparam\">\n\n      <refmeta>\n\t<refentrytitle>ne_strparam</refentrytitle>\n\t<manvolnum>3</manvolnum>\n      </refmeta>\n\n      <refnamediv>\n\t<refname id=\"ne_strparam\">ne_strparam</refname>\n\t<refpurpose>HTTP extended parameter value encoding</refpurpose>\n      </refnamediv>\n\n      <refsynopsisdiv>\n\n\t<funcsynopsis>\n          <funcsynopsisinfo>#include &lt;ne_string.h&gt;</funcsynopsisinfo>\n\n\t  <funcprototype>\n\t    <funcdef>char *<function>ne_strparam</function></funcdef>\n\t    <paramdef>const char *<parameter>charset</parameter></paramdef>\n\t    <paramdef>const char *<parameter>lang</parameter></paramdef>\n\t    <paramdef>const char *<parameter>value</parameter></paramdef>\n\t  </funcprototype>\n\t</funcsynopsis>\n\n      </refsynopsisdiv>\n\n      <refsect1>\n\t<title>Description</title>\n\n\t<para>The <function>ne_strparam</function> function can be\n\tused to encode an extended parameter value for an HTTP header,\n\tas defined in RFC 5987.  The function takes as arguments the\n\t<parameter>value</parameter> to encode, using a given MIME\n\t<parameter>charset</parameter> character set, and\n\t<parameter>lang</parameter> language tag.  The extended\n\tparameter encoding is used in HTTP protocol specifications to\n\tallow easily embedding special characters (such as quote\n\tmarks, separators or non-ASCII) in header values.</para>\n\n        <para>In accordance with RFC 5987, the\n        <parameter>charset</parameter> argument must be either\n        <constant>\"UTF-8\"</constant> or\n        <constant>\"IS0-8859-1\"</constant>, but the\n        <parameter>lang</parameter> argument may be &null;.</para>\n      </refsect1>\n\n      <refsect1>\n\t<title>Return value</title>\n\n        <para>The return value is either:\n\n\t<variablelist>\n\t  <varlistentry>\n            <term>&null;</term>\n            <listitem><simpara>if the value parameter is a \"regular\n            parameter\" and does not need extended\n            encoding</simpara></listitem> </varlistentry>\n            <varlistentry>\n            <term>non-&null;</term>\n            <listitem><simpara>the encoding of the input value as an\n            extended parameter as a NUL-terminated, malloc-allocated\n            string</simpara></listitem>\n\t  </varlistentry>\n        </variablelist></para>\n      </refsect1>\n\n      <refsect1>\n\t<title>History</title>\n\n        <para><function>ne_strparam</function> is\n        available in &neon; 0.32.0 and later.</para>\n      </refsect1>\n\n  <refsect1>\n    <title>See also</title>\n\n    <para><ulink url=\"https://www.rfc-editor.org/rfc/rfc5987.html\"/></para>\n  </refsect1>\n\n</refentry>\n"
  },
  {
    "path": "doc/ref/proxy.xml",
    "content": "     <refentry id=\"refproxy\">\n      \n      <refmeta>\n\t<refentrytitle>ne_session_proxy</refentrytitle>\n\t<manvolnum>3</manvolnum>\n      </refmeta>\n\n      <refnamediv>\n\t<refname id=\"ne_session_proxy\">ne_session_proxy</refname>\n\t<refname id=\"ne_session_socks_proxy\">ne_session_socks_proxy</refname>\n\t<refname id=\"ne_session_system_proxy\">ne_session_system_proxy</refname>\n\t<refname id=\"ne_set_addrlist\">ne_set_addrlist</refname>\n\t<refpurpose>configure proxy servers</refpurpose>\n      </refnamediv>\n      \n      <refsynopsisdiv>\n\t\n\t<funcsynopsis>\n\t  <funcsynopsisinfo>#include &lt;ne_session.h&gt;</funcsynopsisinfo>\n\n\t  <funcprototype>\n\t    <funcdef>void <function>ne_session_proxy</function></funcdef>\n\t    <paramdef>ne_session *<parameter>session</parameter></paramdef>\n\t    <paramdef>const char *<parameter>hostname</parameter></paramdef>\n\t    <paramdef>unsigned int <parameter>port</parameter></paramdef>\n\t  </funcprototype>\n\n\t  <funcprototype>\n\t    <funcdef>void <function>ne_session_system_proxy</function></funcdef>\n\t    <paramdef>ne_session *<parameter>session</parameter></paramdef>\n\t    <paramdef>unsigned int <parameter>flags</parameter></paramdef>\n\t  </funcprototype>\n\n\t  <funcprototype>\n\t    <funcdef>void <function>ne_session_socks_proxy</function></funcdef>\n\t    <paramdef>ne_session *<parameter>session</parameter></paramdef>\n\t    <paramdef>enum ne_sock_sversion <parameter>version</parameter></paramdef>\n\t    <paramdef>const char *<parameter>hostname</parameter></paramdef>\n\t    <paramdef>unsigned int <parameter>port</parameter></paramdef>\n\t    <paramdef>const char *<parameter>username</parameter></paramdef>\n\t    <paramdef>const char *<parameter>password</parameter></paramdef>\n\t  </funcprototype>\n\n\t  <funcprototype>\n\t    <funcdef>void <function>ne_set_addrlist</function></funcdef>\n\t    <paramdef>ne_session *<parameter>session</parameter></paramdef>\n\t    <paramdef>const ne_inet_addr **<parameter>addrlist</parameter></paramdef>\n\t    <paramdef>size_t <parameter>count</parameter></paramdef>\n\t  </funcprototype>\n\n\t</funcsynopsis>\n      </refsynopsisdiv>\n\n      <refsect1>\n\t<title>Description</title>\n\n\t<para>One (and no more than one) of the functions\n\t<function>ne_session_proxy</function>,\n\t<function>ne_session_system_proxy</function>,\n\t<function>ne_session_socks_proxy</function>,\n\t<function>ne_set_addrlist</function> can be used to configure\n\ta proxy server for a given session object.  If more than one\n\tfunction is invoked for any given session object, only the\n\tlast call has effect.  If one of the functions is to be used,\n\tit must be used before the creation of any request object for\n\tthe session.</para>\n\n        <para>The <parameter>hostname</parameter> parameter used with\n        <function>ne_session_proxy</function> and\n        <function>ne_session_socks_proxy</function> must follow the\n        same rules as the <parameter>host</parameter> for\n        <function>ne_session_create</function>; see <xref\n        linkend=\"ne_session_create\"/> for examples.</para>\n        \n        <refsect2>\n          <title>HTTP proxy specification</title>\n          \n          <para>The <function>ne_session_proxy</function> function\n          configures use of an HTTP proxy server for the session, the\n          location of which is given by the\n          <parameter>hostname</parameter> and\n          <parameter>port</parameter> parameters.  If the proxy\n          requires authentication, <xref linkend=\"ne_set_proxy_auth\"/>\n          should be used.</para>\n        </refsect2>\n          \n        <refsect2>\n          <title>System proxy configuration</title>\n          \n          <para>The <function>ne_session_system_proxy</function>\n          function configures the session to use any proxy servers\n          specified by the system configuration.  Support for this\n          function is platform-specific; if unsupported, the function\n          has no effect.</para>\n        </refsect2>\n\n        <refsect2>\n          <title>SOCKS proxy configuration</title>\n          \n          <para>The <function>ne_session_socks_proxy</function>\n          function configures the session to use a SOCKS proxy.  The\n          <parameter>version</parameter> indicates which version of\n          the SOCKS protocol should be used.  The\n          <parameter>hostname</parameter> and\n          <parameter>port</parameter> parameters specify the SOCKS\n          proxy location.  Note that a server with only an IPv6\n          address cannot be used with SOCKS v4 or v4A.  The\n          interpretation of the other arguments depends on the version\n          specified:</para>\n          \n          <variablelist>\n            <varlistentry><term><constant>NE_SOCK_SOCKSV4</constant> (version 4)</term>\n\t    <listitem>\n\t      <simpara>The <parameter>username</parameter> parameter\n\t       must be non-&null;; the <parameter>password</parameter>\n\t       parameter is ignored.</simpara>\n\t    </listitem>\n            </varlistentry>\n\n            <varlistentry><term><constant>NE_SOCK_SOCKSV4A</constant> (version 4A)</term>\n\t    <listitem>\n\t      <simpara>The <parameter>username</parameter> parameter\n\t      must be non-&null;; the <parameter>password</parameter>\n\t      parameter is ignored.</simpara>\n\t    </listitem>\n            </varlistentry>\n\n            <varlistentry><term><constant>NE_SOCK_SOCKSV5</constant> (version 5)</term>\n\t    <listitem>\n\t      <simpara>The <parameter>username</parameter> parameter\n\t      may be &null;; if it is non-&null;,\n\t      the <parameter>password</parameter> parameter must also\n\t      be non-&null;; otherwise, it is ignored..</simpara>\n\t    </listitem>\n            </varlistentry>\n          </variablelist>\n\n        </refsect2>\n\n        <refsect2>\n          <title>Origin server address override</title>\n          \n          <para>The <function>ne_set_addrlist</function> function\n          forces use of an address and port the a specified list when\n          establishing a TCP connection, ignoring the \"real\" hostname\n          and port identifying the origin server for the session (as\n          passed to <function>ne_session_create</function>).  The\n          origin server's \"real\" hostname and port will still be used\n          in the <literal>Host</literal> header in HTTP requests.\n          When a connection is required, the library will iterate\n          through the <parameter>addrlist</parameter> list, attempting\n          to connect to the address <parameter>addrlist[0]</parameter>\n          through to <parameter>addrlist[count-1]</parameter> in turn,\n          until a connection can be established.</para>\n\n        </refsect2>\n\n      </refsect1>\n\n      <refsect1>\n\t<title>Return Values</title>\n\t<para>None of the functions described here has a return\n\tvalue.</para>\n      </refsect1>\n\n      <refsect1>\n\t<title>Examples</title>\n\t<para>Create and destroy a session:</para>\n\t<programlisting>ne_session *sess;\nsess = ne_session_create(\"http\", \"host.example.com\", 80);\nne_session_proxy(sess, \"proxy.example.com\", 3128);\n/* ... use sess ... */\nne_session_destroy(sess);\n</programlisting>\n      </refsect1>\n\n      <refsect1>\n\t<title>See Also</title>\n\n\t<para><xref linkend=\"ne_session_create\"/>, <xref linkend=\"ne_set_proxy_auth\"/></para>\n      </refsect1>\n\n    </refentry>\n"
  },
  {
    "path": "doc/ref/redir.xml",
    "content": "    <refentry id=\"refred\">\n\n      <refmeta>\n\t<refentrytitle>ne_redirect_register</refentrytitle>\n\t<manvolnum>3</manvolnum>\n      </refmeta>\n\n      <refnamediv>\n\t<refname id=\"ne_redirect_register\">ne_redirect_register</refname>\n\t<refname id=\"ne_redirect_location\">ne_redirect_location</refname>\n\t<refpurpose>HTTP request redirect handling</refpurpose>\n      </refnamediv>\n      \n      <refsynopsisdiv>\n\t\n\t<funcsynopsis>\n\n\t  <funcsynopsisinfo>#include &lt;ne_redirect.h&gt;</funcsynopsisinfo>\n\n\t  <funcprototype>\n\t    <funcdef>void <function>ne_redirect_register</function></funcdef>\n\t    <paramdef>ne_session *<parameter>sess</parameter></paramdef>\n\t  </funcprototype>\n\n\t  <funcprototype>\n\t    <funcdef>const ne_uri *<function>ne_redirect_location</function></funcdef>\n\t    <paramdef>ne_session *<parameter>sess</parameter></paramdef>\n\t  </funcprototype>\n\t</funcsynopsis>\n\t\n      </refsynopsisdiv>\n\n      <refsect1>\n\t<title>Description</title>\n\n\t<para>The <type>ne_redirect_register</type> function registers\n\tredirect handling for the session. If a valid redirect (with\n\tstatus code 3xx) response is processed, the request will fail\n\twith the <literal>NE_REDIRECT</literal> error code. The\n\tdestination of the redirect can then be retrieved using\n\t<function>ne_redirect_location</function>.</para>\n\n\t<para>If a redirect was processed, the\n\t<type>ne_redirect_location</type> function returns the\n\tdestination URI of the redirect.</para>\n        \n      </refsect1>\n\n      <refsect1>\n\t<title>Return value</title>\n\n\t<para><function>ne_redirect_location</function> returns\n\t<literal>NULL</literal> if no request has yet been processed,\n\tif the current request was not a redirect, or if the\n\tdestination of the redirect could not be parsed or\n\tresolved. Otherwise it returns a pointer to an\n\t<type>ne_uri</type> object, which remains valid until another\n\trequest is created for the session.</para>\n\n      </refsect1>\n\n      <refsect1>\n\t<title>See also</title>\n\t\n\t<para><xref linkend=\"ne_session_create\"/>.</para>\n\n      </refsect1>\n\n    </refentry>\n"
  },
  {
    "path": "doc/ref/req.xml",
    "content": "    <refentry id=\"refreq\">\n\n      <refmeta>\n\t<refentrytitle>ne_request_create</refentrytitle>\n\t<manvolnum>3</manvolnum>\n      </refmeta>\n\n      <refnamediv>\n\t<refname id=\"ne_request_create\">ne_request_create</refname>\n\t<refname id=\"ne_request_dispatch\">ne_request_dispatch</refname>\n\t<refname id=\"ne_request_destroy\">ne_request_destroy</refname>\n\t<refpurpose>low-level HTTP request handling</refpurpose>\n      </refnamediv>\n      \n      <refsynopsisdiv>\n\t\n\t<funcsynopsis>\n\t  <funcsynopsisinfo>#include &lt;ne_request.h&gt;</funcsynopsisinfo>\n\n\t  <funcprototype>\n\t    <funcdef>ne_request *<function>ne_request_create</function></funcdef>\n\t    <paramdef>ne_session *<parameter>session</parameter></paramdef>\n\t    <paramdef>const char *<parameter>method</parameter></paramdef>\n\t    <paramdef>const char *<parameter>target</parameter></paramdef>\n\t  </funcprototype>\n\n\t  <funcprototype>\n\t    <funcdef>int <function>ne_request_dispatch</function></funcdef>\n\t    <paramdef>ne_request *<parameter>req</parameter></paramdef>\n\t  </funcprototype>\n\n\t  <funcprototype>\n\t    <funcdef>void <function>ne_request_destroy</function></funcdef>\n\t    <paramdef>ne_request *<parameter>req</parameter></paramdef>\n\t  </funcprototype>\n\t</funcsynopsis>\n\t\n      </refsynopsisdiv>\n\n      <refsect1>\n\t<title>Description</title>\n\n\t<para>The <type>ne_request</type> object represents an HTTP\n\trequest and the associated response.  The\n\t<function>ne_request_create</function> function creates a new\n\trequest object for the given <parameter>session</parameter>.\n\tThe target resource for the request is identified by the\n\t<parameter>target</parameter>, parameter, and the method to be\n\tperformed on that resource via the\n\t<parameter>method</parameter> parameter.</para>\n\n<para>The <parameter>target</parameter> string used must conform to\nthe <literal>request-target</literal> definition given in <ulink\nurl=\"https://www.rfc-editor.org/rfc/rfc9112\">RFC 9112</ulink>. Usually\nthis will take the <literal>abolute-path</literal> form, which\noptionally includes a query string.</para>\n\n\t<para>To <emphasis>dispatch</emphasis> a request, and process the response, the\n<function>ne_request_dispatch</function> function can be used.  An\nalternative is to use the (more complex, but more flexible)\ncombination of the <function>ne_begin_request</function>,\n<function>ne_end_request</function>, and\n<function>ne_read_response_block</function> functions; see\n<function>ne_begin_request</function>. <emphasis>Dispatching</emphasis> a request may require\nmultiple iterations of a request being sent and response received, for example\nif authentication is used (see <xref linkend=\"ne_set_server_auth\"/>), or if a persistent\nconnection times out; this is handled internally by <function>ne_request_dispatch</function>.</para>\n\n\n\t<para>To add extra headers in the request, the functions <xref\nlinkend=\"ne_add_request_header\"/> and <xref\nlinkend=\"ne_print_request_header\"/> can be used.  To include a message\nbody with the request, one of the functions\n<function>ne_set_request_body_buffer</function>, <function>ne_set_request_body_fd</function>, or\n<function>ne_set_request_body_provider</function> can be used.</para>\n\n\t<para>The return value of\n<function>ne_request_dispatch</function> indicates merely whether the\nrequest was sent and the response read successfully.  To discover the\nresult of the operation, <xref linkend=\"ne_get_status\"/>, along with\nany processing of the response headers and message body.</para>\n\n\t<para>A request can only be dispatched once: calling\n\t<function>ne_request_dispatch</function> more than once on a\n\tsingle <type>ne_request</type> object produces undefined\n\tbehaviour.  Once all processing associated with the request\n\tobject is complete, use the\n\t<function>ne_request_destroy</function> function to destroy\n        the resources associated with it.  Any subsequent use of the\n\trequest object produces undefined behaviour.</para>\n\n        <para>Request methods are assumed to be <ulink\n        url=\"https://www.rfc-editor.org/rfc/rfc9110.html#name-idempotent-methods\">idempotent</ulink>\n        by default. For a request using a non-idempotent method such\n        as <literal>POST</literal>, the\n        <literal>NE_REQFLAG_IDEMPOTENT</literal> flag must be\n        disabled using <xref linkend=\"ne_set_request_flag\"/>.</para>\n\n      </refsect1>\n\n      <refsect1>\n\t<title>Return value</title>\n\n\t<para>The <function>ne_request_create</function> function\nreturns a pointer to a request object (and never &null;).</para>\n\n\t<para>The <function>ne_request_dispatch</function> function\n\treturns zero if the request was dispatched successfully, and a\n\tnon-zero error code code otherwise, as described in the\n\tfollowing section.</para>\n      </refsect1>\n\n      <refsect1 id=\"error-codes\" xreflabel=\"NE_* error code\">\n\t<title>Error codes</title>\n\n        <para>Error codes have a non-zero value, and correspond to an\n        <literal>NE_*</literal> macro definition, as listed below.\n        Future versions of &neon; may introduce additional error code\n        definitions. Functions which return an error code and have an\n        associated session object set the session error string (see\n        <xref linkend=\"ne_get_error\"/>) unless documented\n        otherwise.</para>\n\n\t<variablelist>\n\t  <varlistentry><term><errorcode>NE_ERROR</errorcode></term>\n\t    <listitem>\n\t      <simpara>Request failed (see session error string)</simpara>\n\t    </listitem>\n\t  </varlistentry>\n\t  <varlistentry><term><errorcode>NE_LOOKUP</errorcode></term>\n\t    <listitem>\n\t      <simpara>The DNS lookup for the server (or proxy server) failed.</simpara>\n\t    </listitem>\n\t  </varlistentry>\n\t  <varlistentry><term><errorcode>NE_AUTH</errorcode></term>\n\t    <listitem>\n\t      <simpara>Authentication failed on the server.</simpara>\n\t    </listitem>\n\t  </varlistentry>\n\t  <varlistentry><term><errorcode>NE_PROXYAUTH</errorcode></term>\n\t    <listitem>\n\t      <simpara>Authentication failed on the proxy server.</simpara>\n\t    </listitem>\n\t  </varlistentry>\n\t  <varlistentry><term><errorcode>NE_CONNECT</errorcode></term>\n\t    <listitem>\n\t      <simpara>A connection to the server could not be established.</simpara>\n\t    </listitem>\n\t  </varlistentry>\n\t  <varlistentry><term><errorcode>NE_TIMEOUT</errorcode></term>\n\t    <listitem>\n\t      <simpara>A timeout occurred while waiting for the server to respond.</simpara>\n\t    </listitem>\n\t  </varlistentry>\n\t  <varlistentry><term><errorcode>NE_REDIRECT</errorcode></term>\n\t    <listitem>\n\t      <simpara>A valid redirect was retuerned. <emphasis>Note:</emphasis> Only returned if redirect handling is registered for the session using <xref linkend=\"ne_redirect_register\"/>.</simpara>\n\t    </listitem>\n\t  </varlistentry>\n\t</variablelist>\n      </refsect1>\n\n      <refsect1>\n\t<title>Notes</title>\n\n\t<para>The <parameter>path</parameter>,\n\t<parameter>method</parameter> and\n\t<parameter>target</parameter> parameters of\n\t<function>ne_request_create</function> are used directly in\n\trequest data without validation, so must not be taken from\n\tuntrusted sources. For example, allowing insertion of\n\tunescaped CR, LF or other control characters in these\n\tparameters may result in unexpected or insecure behaviour.</para>\n\n        <para>&neon; does not impose any length restrictions on\n        request input data.</para>\n\n      </refsect1>\n\n      <refsect1>\n\t<title>Example</title>\n\t\n\t<para>An example of applying a <literal>MKCOL</literal>\n\toperation to the resource at the location \n\t<literal>http://www.example.com/foo/bar/</literal>:</para>\n\n\t<programlisting>ne_session *sess = ne_session_create(\"http\", \"www.example.com\", 80);\nne_request *req = ne_request_create(sess, \"MKCOL\", \"/foo/bar/\");\nif (ne_request_dispatch(req)) {\n   printf(\"Request failed: %s\\n\", ne_get_error(sess));\n}\nne_request_destroy(req);</programlisting>\n      </refsect1>\n\n      <refsect1>\n\t<title>See also</title>\n\t\n\t<para><xref linkend=\"ne_session_create\"/>, <xref linkend=\"ne_get_error\"/>, <xref\nlinkend=\"ne_set_error\"/>, <xref linkend=\"ne_get_status\"/>, <xref\nlinkend=\"ne_add_request_header\"/>, <xref\nlinkend=\"ne_set_request_body_buffer\"/>, <xref linkend=\"ne_set_request_flag\"/>, <xref linkend=\"ne_redirect_register\"/>.</para>\n\n      </refsect1>\n\n    </refentry>\n"
  },
  {
    "path": "doc/ref/reqbody.xml",
    "content": "    <refentry id=\"refreqbody\">\n\n      <refmeta>\n\t<refentrytitle>ne_set_request_body_buffer</refentrytitle>\n\t<manvolnum>3</manvolnum>\n      </refmeta>\n\n      <refnamediv>\n\t<refname id=\"ne_set_request_body_buffer\">ne_set_request_body_buffer</refname>\n\t<refname id=\"ne_set_request_body_fd\">ne_set_request_body_fd</refname>\n\t<refname id=\"ne_set_request_body_provider\">ne_set_request_body_provider</refname>\n\t<refpurpose>include a message body with a request</refpurpose>\n      </refnamediv>\n      \n      <refsynopsisdiv>\n\t\n\t<funcsynopsis>\n\n\t  <funcsynopsisinfo>#include &lt;ne_request.h&gt;</funcsynopsisinfo>\n\n\t  <funcprototype>\n\t    <funcdef>void <function>ne_set_request_body_buffer</function></funcdef>\n\t    <paramdef>ne_request *<parameter>req</parameter></paramdef>\n\t    <paramdef>const char *<parameter>buf</parameter></paramdef>\n\t    <paramdef>size_t <parameter>count</parameter></paramdef>\n\t  </funcprototype>\n\n\t  <funcprototype>\n\t    <funcdef>int <function>ne_set_request_body_fd</function></funcdef>\n\t    <paramdef>ne_request *<parameter>req</parameter></paramdef>\n\t    <paramdef>int <parameter>fd</parameter></paramdef>\n\t    <paramdef>ne_off_t <parameter>begin</parameter></paramdef>\n\t    <paramdef>ne_off_t <parameter>length</parameter></paramdef>\n\t  </funcprototype>\n\n\t  <funcprototype>\n\t    <funcdef>typedef ssize_t (*<function>ne_provide_body</function>)</funcdef>\n\t    <paramdef>void *<parameter>userdata</parameter></paramdef>\n\t    <paramdef>char *<parameter>data</parameter></paramdef>\n\t    <paramdef>size_t <parameter>buflen</parameter></paramdef>\n\t  </funcprototype>\n\n\t  <funcprototype>\n\t    <funcdef>int <function>ne_set_request_body_provider</function></funcdef>\n\t    <paramdef>ne_request *<parameter>req</parameter></paramdef>\n\t    <paramdef>ne_off_t <parameter>length</parameter></paramdef>\n\t    <paramdef>ne_provide_body <parameter>provider</parameter></paramdef>\n\t    <paramdef>void *<parameter>userdata</parameter></paramdef>\n\t  </funcprototype>\n\n\t</funcsynopsis>\n\t\n      </refsynopsisdiv>\n\n      <refsect1>\n\t<title>Description</title>\n\n\t<para>The <function>ne_set_request_body_buffer</function>\nfunction specifies that a message body should be included with the\nbody, which is stored in the <parameter>count</parameter> bytes buffer\n<parameter>buf</parameter>.</para>\n\n\t<para>The <function>ne_set_request_body_fd</function> function\ncan be used to include a message body with a request which is read\nfrom a file descriptor.  The body is read from the file descriptor\n<parameter>fd</parameter>, which must be a associated with a seekable\nfile (not a pipe, socket, or FIFO).  <parameter>count</parameter>\nbytes are read, beginning at offset <parameter>begin</parameter>\n(hence, passing <parameter>begin</parameter> as zero means the body is read\nfrom the beginning of the file).</para>\n\n        <para>For both above functions, the source of the request\n        body must survive until the request has been dispatched;\n        neither the memory buffer passed to\n        <function>ne_set_request_body_buffer</function> nor the file\n        descriptor passed to\n        <function>ne_set_request_body_fd</function> are copied\n        internally.</para>\n\n\t<para>The <function>ne_set_request_body_provider</function>\n\tfunction can be used to include a message body with a request\n\twhich is provided by a callback function. The body length\n\tpassed in the <parameter>length</parameter> paramater must be\n\tpositive, or if a chunked request body is required, as covered\n\tbelow, <literal>-1</literal> can be used.</para>\n\n        <para>Before sending the body, the callback is invoked once\n        with the <parameter>buflen</parameter> parameter as\n        <literal>0</literal>. The body is then read by invoking the\n        callback repeatedly until it returns <literal>0</literal>\n        indicating the end-of-body. The callback return value must be\n        as follows:\n\n\t<variablelist>\n\t  <varlistentry>\n            <term>less than <literal>0</literal></term>\n\t    <listitem><simpara>An error; the request will be\n\t    aborted. The session error string must be set via\n\t    <function>ne_set_error</function>.</simpara>\n\t    </listitem>\n\t  </varlistentry>\n\t  <varlistentry>\n            <term><literal>0</literal></term>\n\t    <listitem><simpara>End of body.</simpara>\n\t    </listitem>\n\t  </varlistentry>\n\t  <varlistentry>\n            <term>between <literal>0</literal> and\n            <constant>buflen</constant></term>\n\t    <listitem><simpara>Number of bytes of request body data.</simpara>\n\t    </listitem>\n\t  </varlistentry>\n        </variablelist></para>\n\n        <refsect2>\n          <title>Chunked request bodies</title>\n          \n          <para>Chunked request bodies are only sent when\n          <function>ne_set_request_body_provider</function> is used\n          and <literal>-1</literal> is passed as the\n          <parameter>length</parameter>. In this case, the length of\n          the request body does not have to be determined ahead of\n          time. The end of the request body is indicated by returning\n          <literal>0</literal> from the callback function.</para>\n          \n          <para>Before using a chunked request body, the caller must\n          determine that HTTP/1.1 is supported (by the origin server\n          and any HTTP proxy server configured). This can be done by\n          testing that <function>ne_version_pre_http11</function>\n          returns zero after performing an <literal>OPTIONS</literal>\n          or <literal>HEAD</literal> request.</para>\n        </refsect2>\n        \n      </refsect1>\n\n      <refsect1>\n\t<title>See also</title>\n\n\t<para><xref linkend=\"ne_request_create\"/>, <xref\n\tlinkend=\"ne_set_error\"/></para>\n      </refsect1>\n\n    </refentry>\n"
  },
  {
    "path": "doc/ref/reqflags.xml",
    "content": "<refentry id=\"refreqflags\">\n\n  <refmeta>\n    <refentrytitle>ne_set_request_flag</refentrytitle>\n    <manvolnum>3</manvolnum>\n  </refmeta>\n\n  <refnamediv>\n    <refname id=\"ne_set_request_flag\">ne_set_request_flag</refname>\n    <refname id=\"ne_get_request_flag\">ne_get_request_flag</refname>\n    <refpurpose>set and retrieve per-request flags</refpurpose>\n  </refnamediv>\n  \n  <refsynopsisdiv>\n\n    <funcsynopsis>\n\n      <funcsynopsisinfo>#include &lt;ne_request.h&gt;</funcsynopsisinfo>\n\n      <funcprototype>\n        <funcdef>void <function>ne_set_request_flag</function></funcdef>\n        <paramdef>ne_request *<parameter>req</parameter></paramdef>\n        <paramdef>ne_request_flag <parameter>flag</parameter></paramdef>\n        <paramdef>int <parameter>value</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>int <function>ne_get_request_flag</function></funcdef>\n        <paramdef>ne_request *<parameter>req</parameter></paramdef>\n        <paramdef>ne_request_flag <parameter>flag</parameter></paramdef>\n      </funcprototype>\n\n    </funcsynopsis>\n\n  </refsynopsisdiv>\n\n  <refsect1>\n    <title>Description</title>\n\n    <para>The <function>ne_set_request_flag</function> function\n    enables or disables a per-request flag.  Passing a non-zero\n    <parameter>value</parameter> argument enables the flag, and zero\n    disables it.</para>\n\n    <para>The following flags are defined:</para>\n\n\t<variablelist>\n\t  <varlistentry>\n            <term><constant>NE_REQFLAG_EXPECT100</constant> (default off)</term>\n\t    <listitem>\n\t      <simpara>enable this flag to use the \"Expect:\n\t      100-continue\" feature of HTTP/1.1, which allows the\n\t      server to process request headers without reading the\n\t      entire request body.  This saves time and bandwidth if\n\t      the server gives an authentication challenge (requiring\n\t      the request to be resent), but has interoperability\n\t      problems with some older servers.</simpara>\n\t    </listitem>\n\t  </varlistentry>\n\t  <varlistentry>\n            <term><constant>NE_REQFLAG_IDEMPOTENT</constant>  (default on)</term>\n\t    <listitem>\n\t      <simpara>disable this flag if the request uses a\n\t      non-idempotent method such as\n\t      <literal>POST</literal></simpara>\n\t    </listitem>\n\t  </varlistentry>\n\t  <varlistentry>\n            <term><constant>NE_REQFLAG_1XXTIMEOUT</constant> (default on)</term>\n\t    <listitem>\n\t      <simpara>disable this flag to disable overall timeout\n\t      when reading interim (1xx) responses</simpara>\n\t    </listitem>\n\t  </varlistentry>\n        </variablelist>\n  </refsect1>\n\n  <refsect1>\n    <title>Return value</title>\n\n    <para>The <function>ne_get_request_flag</function> function returns\n    zero if a flag is disabled, less than zero if the flag is not\n    supported, or greater than zero if the flag is enabled.</para>\n  </refsect1>\n\n  <refsect1>\n    <title>See also</title>\n\n    <para><xref linkend=\"ne_request_create\"/>.</para>\n\n  </refsect1>\n\n</refentry>\n"
  },
  {
    "path": "doc/ref/reqhdr.xml",
    "content": "    <refentry id=\"refreqhdr\">\n\n      <refmeta>\n\t<refentrytitle>ne_add_request_header</refentrytitle>\n\t<manvolnum>3</manvolnum>\n      </refmeta>\n\n      <refnamediv>\n\t<refname id=\"ne_add_request_header\">ne_add_request_header</refname>\n\t<refname id=\"ne_print_request_header\">ne_print_request_header</refname>\n\t<refpurpose>add headers to a request</refpurpose>\n      </refnamediv>\n      \n      <refsynopsisdiv>\n\t\n\t<funcsynopsis>\n\n\t  <funcsynopsisinfo>#include &lt;ne_request.h&gt;</funcsynopsisinfo>\n\n\t  <funcprototype>\n\t    <funcdef>void <function>ne_add_request_header</function></funcdef>\n\t    <paramdef>ne_request *<parameter>request</parameter></paramdef>\n\t    <paramdef>const char *<parameter>name</parameter></paramdef>\n\t    <paramdef>const char *<parameter>value</parameter></paramdef>\n\t  </funcprototype>\n\n\t  <funcprototype>\n\t    <funcdef>void <function>ne_print_request_header</function></funcdef>\n\t    <paramdef>ne_request *<parameter>request</parameter></paramdef>\n\t    <paramdef>const char *<parameter>name</parameter></paramdef>\n\t    <paramdef>const char *<parameter>format</parameter></paramdef>\n\t    <paramdef>...</paramdef>\n\t  </funcprototype>\n\n\t</funcsynopsis>\n\t\n      </refsynopsisdiv>\n\n      <refsect1>\n\t<title>Description</title>\n\n\t<para>The functions <function>ne_add_request_header</function>\nand <function>ne_print_request_header</function> can be used to add\nheaders to a request, before it is sent.</para>\n\n\t<para><function>ne_add_request_header</function> simply adds a\nheader of given <parameter>name</parameter>, with given\n<parameter>value</parameter>.</para>\n\n\t<para><function>ne_print_request_header</function> adds a\nheader of given <parameter>name</parameter>, taking the value from the\n<function>printf</function>-like <parameter>format</parameter> string\nparameter and subsequent variable-length argument list.</para>\n\n      </refsect1>\n\n      <refsect1>\n\t<title>See also</title>\n\n\t<para><xref linkend=\"ne_request_create\"/></para>\n      </refsect1>\n\n    </refentry>\n"
  },
  {
    "path": "doc/ref/reqtgt.xml",
    "content": "<refentry id=\"refreqtarget\">\n\n  <refmeta>\n    <refentrytitle>ne_get_request_target</refentrytitle>\n    <manvolnum>3</manvolnum>\n  </refmeta>\n\n  <refnamediv>\n    <refname id=\"ne_get_request_target\">ne_get_request_target</refname>\n    <refpurpose>retrieve request target</refpurpose>\n  </refnamediv>\n  \n  <refsynopsisdiv>\n\n    <funcsynopsis>\n\n      <funcsynopsisinfo>#include &lt;ne_request.h&gt;</funcsynopsisinfo>\n\n      <funcprototype>\n        <funcdef>const ne_uri *<function>ne_get_request_target</function></funcdef>\n        <paramdef>ne_request *<parameter>req</parameter></paramdef>\n      </funcprototype>\n\n    </funcsynopsis>\n\n  </refsynopsisdiv>\n\n  <refsect1>\n    <title>Description</title>\n\n    <para>The <function>ne_get_request_target</function> returns the\n    request target URI as a pointer to an\n    <structname>ne_uri</structname> object. The \"target resource\" of a\n    request is defined per <ulink\n    url=\"https://www.rfc-editor.org/rfc/rfc9110.html#section-7.1\">Section\n    7.1 of RFC 9110</ulink> and is derived from the parameters used to\n    create the request with <xref linkend=\"ne_request_create\"/> and\n    the parameters used to create the session with <xref\n    linkend=\"ne_session_create\"/>.</para>\n\n  </refsect1>\n\n  <refsect1>\n    <title>Return value</title>\n\n    <para>The <function>ne_get_request_target</function> function\n    returns a <structname>ne_uri</structname>, or &null; if it was not\n    possible to create the target URI. The latter can only occur if\n    the path used to create the request object was not a valid URI\n    path. Note that the <structfield>path</structfield> field of the\n    returned object can be the empty string if the\n    <literal>authority-form</literal> of the URI is used.</para>\n\n  </refsect1>\n\n  <refsect1>\n    <title>History</title>\n    \n    <para><function>ne_get_request_target</function> is available in\n    &neon; 0.34.0 and later.</para>\n  </refsect1>\n  \n  <refsect1>\n    <title>See also</title>\n\n    <para><xref linkend=\"ne_request_create\"/>, <xref\n    linkend=\"ne_session_create\"/>.</para>\n\n  </refsect1>\n\n</refentry>\n"
  },
  {
    "path": "doc/ref/resolve.xml",
    "content": "<refentry id=\"refresolve\">\n\n  <refmeta>\n    <refentrytitle>ne_addr_resolve</refentrytitle>\n    <manvolnum>3</manvolnum>\n  </refmeta>\n\n  <refnamediv>\n    <refname id=\"ne_addr_resolve\">ne_addr_resolve</refname>\n    <refname id=\"ne_addr_result\">ne_addr_result</refname>\n    <refname id=\"ne_addr_first\">ne_addr_first</refname>\n    <refname id=\"ne_addr_next\">ne_addr_next</refname>\n    <refname id=\"ne_addr_error\">ne_addr_error</refname>\n    <refname id=\"ne_addr_canonical\">ne_addr_canonical</refname>\n    <refname id=\"ne_addr_destroy\">ne_addr_destroy</refname>\n    <refpurpose>functions to resolve hostnames to addresses</refpurpose>\n  </refnamediv>\n  \n  <refsynopsisdiv>\n\n    <funcsynopsis>\n\n      <funcsynopsisinfo>#include &lt;ne_socket.h&gt;</funcsynopsisinfo>\n\n      <funcprototype>\n        <funcdef>ne_sock_addr *<function>ne_addr_resolve</function></funcdef>\n        <paramdef>const char *<parameter>hostname</parameter></paramdef>\n        <paramdef>int <parameter>flags</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>int <function>ne_addr_result</function></funcdef>\n        <paramdef>const ne_sock_addr *<parameter>addr</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>const ne_inet_addr *<function>ne_addr_first</function></funcdef>\n        <paramdef>ne_sock_addr *<parameter>addr</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>const ne_inet_addr *<function>ne_addr_next</function></funcdef>\n        <paramdef>ne_sock_addr *<parameter>addr</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>char *<function>ne_addr_error</function></funcdef>\n        <paramdef>const ne_sock_addr *<parameter>addr</parameter></paramdef>\n        <paramdef>char *<parameter>buffer</parameter></paramdef>\n        <paramdef>size_t <parameter>bufsiz</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>const char *<function>ne_addr_canonical</function></funcdef>\n        <paramdef>const ne_sock_addr *<parameter>addr</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>void <function>ne_addr_destroy</function></funcdef>\n        <paramdef>ne_sock_addr *<parameter>addr</parameter></paramdef>\n      </funcprototype>\n\n    </funcsynopsis>\n\n  </refsynopsisdiv>\n\n  <refsect1>\n    <title>Description</title>\n\n    <para>The <function>ne_addr_resolve</function> function resolves\n    the given <parameter>hostname</parameter>, returning an\n    <type>ne_sock_addr</type> object representing the address (or\n    addresses) associated with the hostname.  The\n    <parameter>flags</parameter> parameter should be zero, or if\n    <literal>NE_ADDR_CANON</literal> used, the canonical name for\n    the hostname will be determined.</para>\n\n    <para>The <parameter>hostname</parameter> passed to\n    <function>ne_addr_resolve</function> can be a DNS hostname\n    (e.g. <literal>\"www.example.com\"</literal>) or an IPv4 dotted quad\n    (e.g. <literal>\"192.0.34.72\"</literal>); or, on systems which\n    support IPv6, an IPv6 hex address, which may be enclosed in\n    brackets, e.g. <literal>\"[::1]\"</literal>.</para>\n\n    <para>To determine whether the hostname was successfully resolved,\n    the <function>ne_addr_result</function> function is used, which\n    returns non-zero if an error occurred.  If an error did occur, the\n    <function>ne_addr_error</function> function can be used, which\n    will copy the error string into a given\n    <parameter>buffer</parameter> (of size\n    <parameter>bufsiz</parameter>).</para>\n\n    <para>The functions <function>ne_addr_first</function> and\n    <function>ne_addr_next</function> are used to retrieve the\n    Internet addresses associated with an address object which has\n    been successfully resolved.  <function>ne_addr_first</function>\n    returns the first address; <function>ne_addr_next</function>\n    returns the next address after the most recent call to\n    <function>ne_addr_next</function> or\n    <function>ne_addr_first</function>, or &null; if there are no more\n    addresses.  The <type>ne_inet_addr</type> pointer returned by\n    these functions can be passed to\n    <function>ne_sock_connect</function> to connect a socket.</para>\n\n    <para>If the <literal>NE_ADDR_CANON</literal> flag was used with\n    <function>ne_addr_resolve</function>, the canonical hostname can\n    be retrieved using <function>ne_addr_canonical</function>.</para>\n\n    <para>After the address object has been used, it should be\n    destroyed using <function>ne_addr_destroy</function>.</para>\n\n  </refsect1>\n\n  <refsect1>\n    <title>Return value</title>\n\n    <para><function>ne_addr_resolve</function> returns a pointer to an\n    address object, and never &null;.\n    <function>ne_addr_error</function> returns the\n    <parameter>buffer</parameter> parameter.</para>\n\n  </refsect1>\n\n  <refsect1>\n    <title>Examples</title>\n\n    <para>The code below prints out the set of addresses associated\n    with the hostname <literal>www.google.com</literal>.</para>\n\n    <programlisting>ne_sock_addr *addr;\nchar buf[256];\n\naddr = ne_addr_resolve(\"www.google.com\", 0);\nif (ne_addr_result(addr)) {\n    printf(\"Could not resolve www.google.com: %s\\n\",\n           ne_addr_error(addr, buf, sizeof buf));\n} else {\n    const ne_inet_addr *ia;\n    printf(\"www.google.com:\");\n    for (ia = ne_addr_first(addr); ia != NULL; ia = ne_addr_next(addr)) {\n        printf(\" %s\", ne_iaddr_print(ia, buf, sizeof buf));\n    }\n    putchar('\\n');\n}\nne_addr_destroy(addr);\n</programlisting>\n  </refsect1>\n\n  <refsect1>\n    <title>History</title>\n\n    <para><function>ne_addr_canonical</function> was added in &neon; 0.30.0.</para>\n  </refsect1>\n\n  <refsect1>\n    <title>See also</title>\n\n    <para><xref linkend=\"ne_iaddr_print\"/></para>\n  </refsect1>\n\n</refentry>\n\n"
  },
  {
    "path": "doc/ref/respbody.xml",
    "content": "    <refentry id=\"refrespbody\">\n\n      <refmeta>\n\t<refentrytitle>ne_read_response_to_fd</refentrytitle>\n\t<manvolnum>3</manvolnum>\n      </refmeta>\n\n      <refnamediv>\n\t<refname id=\"ne_read_response_to_fd\">ne_read_response_to_fd</refname>\n\t<refname id=\"ne_read_response_to_buffer\">ne_read_response_to_buffer</refname>\n\t<refpurpose>read a response body</refpurpose>\n      </refnamediv>\n\n      <refsynopsisdiv>\n\t<funcsynopsis>\n\t  <funcsynopsisinfo>#include &lt;ne_request.h&gt;</funcsynopsisinfo>\n\n\t  <funcprototype>\n\t    <funcdef>int <function>ne_read_response_to_fd</function></funcdef>\n\t    <paramdef>ne_request *<parameter>req</parameter></paramdef>\n\t    <paramdef>int <parameter>fd</parameter></paramdef>\n\t  </funcprototype>\n\n\t  <funcprototype>\n\t    <funcdef>int <function>ne_read_response_to_buffer</function></funcdef>\n\t    <paramdef>ne_request *<parameter>req</parameter></paramdef>\n\t    <paramdef>char *<parameter>data</parameter></paramdef>\n\t    <paramdef>size_t *<parameter>buflen</parameter></paramdef>\n\t  </funcprototype>\n\t</funcsynopsis>\n      </refsynopsisdiv>\n\n      <refsect1>\n\t<title>Description</title>\n\n\t<para>To read an HTTP response body the functions\n\t<function>ne_read_response_to_fd</function> and\n\t<function>ne_read_response_to_buffer</function> can be used.\n\tThese functions are wrappers for\n\t<function>ne_read_response_block</function> and must be called\n\tonly after <function>ne_begin_request</function> has been\n\tcalled successfully for the request.</para>\n\n\t<para>The <function>ne_read_response_to_fd</function> function\n\twrites the response body content to the file descriptor passed\n\tas the <parameter>fd</parameter> parameter.</para>\n\n\t<para>The <function>ne_read_response_to_buffer</function>\n\tfunction writes the response body content to the buffer passed\n\tas the <parameter>buf</parameter> parameter, which has length\n\tpassed via the *<parameter>buflen</parameter> parameter. On\n\tsuccess, the *<parameter>buflen</parameter> is updated with\n\tthe number of bytes written to the buffer.</para>\n\n\t<para>After the response body has been read successfully,\n\t<function>ne_end_request</function> must be called. If a\n\tfailure occurs while reading the response body, the connection\n\tmust be closed using <xref\n\tlinkend=\"ne_close_connection\"/>.</para>\n      </refsect1>\n\n      <refsect1>\n\t<title>Return value</title>\n\n\t<para>Both functions return zero on success, or an <xref\n\tlinkend=\"error-codes\"/> on failure. The\n\t<function>ne_read_response_to_buffer</function> function\n\treturns <literal>NE_FAILED</literal> if the response message\n\tlength is larger than the buffer length.</para>\n      </refsect1>\n\n      <refsect1>\n        <title>History</title>\n\n        <para><function>ne_read_response_to_buffer</function> is available\n        in &neon; 0.36.0 and later.</para>\n      </refsect1>\n\n      <refsect1>\n\t<title>See also</title>\n\n\t<para><xref linkend=\"ne_request_create\"/>, <xref\n\tlinkend=\"ne_set_error\"/></para>\n      </refsect1>\n    </refentry>\n"
  },
  {
    "path": "doc/ref/resphdr.xml",
    "content": "<refentry id=\"refresphdr\">\n\n  <refmeta>\n    <refentrytitle>ne_get_response_header</refentrytitle>\n    <manvolnum>3</manvolnum>\n  </refmeta>\n\n  <refnamediv>\n    <refname id=\"ne_get_response_header\">ne_get_response_header</refname>\n    <refname id=\"ne_get_response_trailer\">ne_get_response_trailer</refname>\n    <refname id=\"ne_response_header_iterate\">ne_response_header_iterate</refname>\n    <refname id=\"ne_response_trailer_iterate\">ne_response_trailer_iterate</refname>\n    <refpurpose>functions to access response headers and trailers</refpurpose>\n  </refnamediv>\n  \n  <refsynopsisdiv>\n\n    <funcsynopsis>\n\n      <funcsynopsisinfo>#include &lt;ne_request.h&gt;</funcsynopsisinfo>\n\n      <funcprototype>\n        <funcdef>const char *<function>ne_get_response_header</function></funcdef>\n        <paramdef>ne_request *<parameter>request</parameter></paramdef>\n        <paramdef>const char *<parameter>name</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>const char *<function>ne_get_response_trailer</function></funcdef>\n        <paramdef>ne_request *<parameter>req</parameter></paramdef>\n        <paramdef>const char *<parameter>name</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>void *<function>ne_response_header_iterate</function></funcdef>\n        <paramdef>ne_request *<parameter>request</parameter></paramdef>\n        <paramdef>void *<parameter>cursor</parameter></paramdef>\n        <paramdef>const char **<parameter>name</parameter></paramdef>\n        <paramdef>const char **<parameter>value</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>void *<function>ne_response_trailer_iterate</function></funcdef>\n        <paramdef>ne_request *<parameter>request</parameter></paramdef>\n        <paramdef>void *<parameter>cursor</parameter></paramdef>\n        <paramdef>const char **<parameter>name</parameter></paramdef>\n        <paramdef>const char **<parameter>value</parameter></paramdef>\n      </funcprototype>\n    </funcsynopsis>\n  </refsynopsisdiv>\n\n  <refsect1>\n    <title>Description</title>\n\n    <para>To retrieve the value of a response header field, the\n    <function>ne_get_response_header</function> function can be used,\n    and is given the name of the header to return. If multiple HTTP\n    response headers are received with the same name, their values are\n    combined together in a comma-separated list.</para>\n\n    <para>To retrieve the value of a header from a chunked response\n    trailer section (sent after, rather than before, the response\n    body), <function>ne_get_response_trailer</function> can be\n    used. This function otherwise has the same semantics as\n    <function>ne_get_response_header</function>. Note that trailer\n    fields are used rarely and should be interpreted with care, see\n    <ulink\n    url=\"https://www.rfc-editor.org/rfc/rfc9110.html#name-trailer-fields\">RFC\n    9110 §6.5</ulink>.</para>\n\n    <para>To iterate over all the response headers returned, the\n    <function>ne_response_header_iterate</function> function can be\n    used.  This function takes a <parameter>cursor</parameter>\n    parameter which should be &null; to retrieve the first header. The\n    function stores the name and value of the next header header in\n    the <parameter>name</parameter> and <parameter>value</parameter>\n    parameters, and returns a new cursor pointer which can be passed\n    to <function>ne_response_header_iterate</function> to retrieve the\n    next header.</para>\n\n    <para>The <function>ne_response_trailer_iterate</function>\n    function has the same semantics as\n    <function>ne_response_header_iterate</function> except it operates\n    on the response trailer fields rather than the header\n    section.</para>\n  </refsect1>\n\n  <refsect1>\n    <title>Return value</title>\n\n    <para><function>ne_get_response_header</function> and\n    <function>ne_get_response_trailer</function> each return a string,\n    or &null; if no header or trailer field with that name was found.\n    The return value pointer is valid only until the next call to\n    <function>ne_begin_request</function> or\n    <function>ne_request_destroy</function> for the same request.</para>\n\n    <para>Likewise, the cursor, names, and values returned by\n    <function>ne_response_header_iterate</function> or\n    <function>ne_response_trailer_iterate</function> are only valid\n    until the next call to <function>ne_begin_request</function> or\n    until the request object is destroyed.</para>\n  </refsect1>\n\n  <refsect1>\n    <title>Examples</title>\n\n    <para>The following code will output the value of the\n    <literal>Last-Modified</literal> header for a resource:</para>\n\n    <programlisting>ne_request *req = ne_request_create(sess, \"GET\", \"/foo.txt\");\nif (ne_request_dispatch(req) == NE_OK) {\n    const char *mtime = ne_get_response_header(req, \"Last-Modified\");\n    if (mtime) {\n        printf(\"/foo.txt has last-modified value %s\\n\", mtime);\n    }\n}\nne_request_destroy(req);</programlisting>\n\n  </refsect1>\n\n  <refsect1>\n    <title>History</title>\n\n    <para><function>ne_get_response_trailer</function> and\n    <function>ne_response_trailer_iterate</function> are available in\n    &neon; 0.37.0 and later. In older releases, trailer fields were\n    merged with normal response headers and could be accessed using\n    <function>ne_get_response_header</function> or\n    <function>ne_response_header_iterate</function>.</para>\n  </refsect1>\n\n  <refsect1>\n    <title>See also</title>\n\n    <para><xref linkend=\"ne_request_create\"/>, <xref\n    linkend=\"ne_request_destroy\"/>.</para>\n  </refsect1>\n\n</refentry>\n\n"
  },
  {
    "path": "doc/ref/sess.xml",
    "content": "     <refentry id=\"refsess\">\n      \n      <refmeta>\n\t<refentrytitle>ne_session_create</refentrytitle>\n\t<manvolnum>3</manvolnum>\n      </refmeta>\n\n      <refnamediv>\n\t<refname id=\"ne_session_create\">ne_session_create</refname>\n\t<refname id=\"ne_close_connection\">ne_close_connection</refname>\n\t<refname id=\"ne_session_destroy\">ne_session_destroy</refname>\n\t<refpurpose>set up HTTP sessions</refpurpose>\n      </refnamediv>\n      \n      <refsynopsisdiv>\n\t\n\t<funcsynopsis>\n\t  <funcsynopsisinfo>#include &lt;ne_session.h&gt;</funcsynopsisinfo>\n\t  <funcprototype>\n\t    <funcdef>ne_session *<function>ne_session_create</function></funcdef>\n\t    <paramdef>const char *<parameter>scheme</parameter></paramdef>\n\t    <paramdef>const char *<parameter>host</parameter></paramdef>\n\t    <paramdef>unsigned int <parameter>port</parameter></paramdef>\n\t  </funcprototype>\n\n\t  <funcprototype>\n\t    <funcdef>void <function>ne_close_connection</function></funcdef>\n\t    <paramdef>ne_session *<parameter>session</parameter></paramdef>\n\t  </funcprototype>\n\n\t  <funcprototype>\n\t    <funcdef>void <function>ne_session_destroy</function></funcdef>\n\t    <paramdef>ne_session *<parameter>session</parameter></paramdef>\n\t  </funcprototype>\n\n\t</funcsynopsis>\n      </refsynopsisdiv>\n\n      <refsect1>\n\t<title>Description</title>\n\n\t<para>An <type>ne_session</type> object represents an HTTP\nsession - a logical grouping of a sequence of HTTP requests made to a\ncertain server. Any requests made using the session can use a\npersistent connection, share cached authentication credentials and any\nother common attributes.</para>\n\n\t<para>A new HTTP session is created using the\n<function>ne_session_create</function> function; the \n<parameter>host</parameter> and <parameter>port</parameter>\nparameters specify the origin server to use, along with\nthe <parameter>scheme</parameter> (usually <literal>\"http\"</literal>).\nBefore the first use of <function>ne_session_create</function> in a\nprocess, <xref linkend=\"ne_sock_init\"/> must have been called to\nperform any global initialization needed by any libraries used by\n&neon;.</para>\n\n\t<para>To enable SSL/TLS for the session, pass the string\n\t<literal>\"https\"</literal> as the\n\t<parameter>scheme</parameter>, and either register a\n\tcertificate verification function (see <xref\n\tlinkend=\"ne_ssl_set_verify\"/>) or trust the appropriate\n\tcertificate (see <xref linkend=\"ne_ssl_trust_cert\"/>, <xref\n\tlinkend=\"ne_ssl_trust_default_ca\"/>).</para>\n\n        <para>The <parameter>host</parameter> parameter must follow\n        the \"<literal>host</literal>\" grammar in <ulink\n        url=\"https://www.rfc-editor.org/rfc/rfc3986#section-3.2.2\">Section 3.2.2 of RFC 3986</ulink>,\n        which can be an IP-literal or registered (DNS) hostname. Valid\n        examples of each: <literal>\"198.51.100.42\"</literal> (IPv4\n        literal address), <literal>\"[2001:db8::42]\"</literal> (IPv6\n        literal, which <emphasis>MUST</emphasis> be enclosed in square\n        brackets), or <literal>\"www.example.com\"</literal> (DNS\n        hostname). The <ulink\n        url=\"https://www.rfc-editor.org/rfc/rfc6874\">RFC 6874</ulink>\n        syntax for scoped IPv6 link-local literal addresses is also\n        permitted, for example <literal>\"[fe80::1%25eth0]\"</literal>.\n        </para>\n\n        <para>The <parameter>scheme</parameter> parameter is used to\n        determine the URI for resources identified during request\n        handling. Other than special handling of the string\n        <literal>\"https\"</literal>, no other interpretation or\n        checking of the <parameter>scheme</parameter> is\n        performed. For example, if an HTTP-to-FTP proxy is configured,\n        a scheme of <literal>\"ftp\"</literal> could be used to access\n        resources.</para>\n\n\t<para>To use a proxy server for the session, it must be\n\tconfigured (see <xref linkend=\"ne_session_proxy\"/>) before any\n\trequests are created from session object.</para>\n\n        <para>Further per-session options may be changed using the\n        <xref linkend=\"ne_set_session_flag\"/> interface.</para>\n\n\t<para>If it is known that the session will not be used for a\nsignificant period of time, <function>ne_close_connection</function>\ncan be called to close the connection, if one remains open.  Use of\nthis function is entirely optional, but it must not be called if there\nis a request active using the session.</para>\n\n\t<para>Once a session has been completed,\n\t<function>ne_session_destroy</function> must be called to\n\tdestroy the resources associated with the session.  Any\n\tsubsequent use of the session pointer produces undefined\n\tbehaviour.  The session object must not be destroyed until\n\tafter all associated request objects have been\n\tdestroyed.</para>\n\n      </refsect1>\n\n      <refsect1>\n\t<title>Notes</title>\n\n        <para>If a hostname is passed to\n<function>ne_session_create</function>, it will be resolved when the first\nrequest using the session is dispatched; a DNS resolution failure can\nonly be detected at that time (using the <literal>NE_LOOKUP</literal>\nerror code); see <xref linkend=\"ne_request_dispatch\"/> for\ndetails.</para>\n\n      </refsect1>\n\n      <refsect1>\n\t<title>Return Values</title>\n\t<para><function>ne_session_create</function> will return\n\ta pointer to a new session object (and never &null;).</para>\n      </refsect1>\n\n      <refsect1>\n\t<title>Examples</title>\n\t<para>Create and destroy a session:</para>\n\t<programlisting>ne_session *sess;\nsess = ne_session_create(\"http\", \"host.example.com\", 80);\n/* ... use sess ... */\nne_session_destroy(sess);\n</programlisting>\n      </refsect1>\n\n      <refsect1>\n        <title>History</title>\n        \n        <para>The <parameter>scheme</parameter> passed to <function>ne_session_create</function> is lower-cased internally from &neon; 0.37.0 onward, so passing <literal>\"HtTpS\"</literal> and <literal>\"https\"</literal> are equivalent. In earlier releases, the scheme is case-sensitive.</para>\n        \n      </refsect1>\n\n      <refsect1>\n\t<title>See Also</title>\n\n\t<para><xref linkend=\"ne_ssl_set_verify\"/>, <xref linkend=\"ne_ssl_trust_cert\"/>, <xref linkend=\"ne_sock_init\"/>, <xref linkend=\"ne_set_session_flag\"/>, <xref linkend=\"ne_session_proxy\"/></para>\n      </refsect1>\n\n    </refentry>\n"
  },
  {
    "path": "doc/ref/sessflags.xml",
    "content": "<refentry id=\"refsessflags\">\n\n  <refmeta>\n    <refentrytitle>ne_set_session_flag</refentrytitle>\n    <manvolnum>3</manvolnum>\n  </refmeta>\n\n  <refnamediv>\n    <refname id=\"ne_set_session_flag\">ne_set_session_flag</refname>\n    <refname id=\"ne_get_session_flag\">ne_get_session_flag</refname>\n    <refpurpose>set and retrieve session flags</refpurpose>\n  </refnamediv>\n  \n  <refsynopsisdiv>\n\n    <funcsynopsis>\n\n      <funcsynopsisinfo>#include &lt;ne_request.h&gt;</funcsynopsisinfo>\n\n      <funcprototype>\n        <funcdef>void <function>ne_set_session_flag</function></funcdef>\n        <paramdef>ne_session *<parameter>sess</parameter></paramdef>\n        <paramdef>ne_session_flag <parameter>flag</parameter></paramdef>\n        <paramdef>int <parameter>value</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>int <function>ne_get_session_flag</function></funcdef>\n        <paramdef>ne_session *<parameter>sess</parameter></paramdef>\n        <paramdef>ne_session_flag <parameter>flag</parameter></paramdef>\n      </funcprototype>\n\n    </funcsynopsis>\n\n  </refsynopsisdiv>\n\n  <refsect1>\n    <title>Description</title>\n\n    <para>The <function>ne_set_session_flag</function> function\n    enables or disables a session flag.  Passing a non-zero\n    <parameter>value</parameter> argument enables the flag, and zero\n    disables it.</para>\n\n    <para>The following flags are defined:</para>\n\n\t<variablelist>\n\t  <varlistentry>\n            <term><constant>NE_SESSFLAG_PERSIST</constant> (default on)</term>\n\t    <listitem>\n\t      <simpara>disable this flag to prevent use of persistent\n\t      connections</simpara>\n\t    </listitem>\n\t  </varlistentry>\n\t  <varlistentry>\n            <term><constant>NE_SESSFLAG_ICYPROTO</constant> (default off)</term>\n\t    <listitem>\n\t      <simpara>enable this flag to enable support for non-HTTP\n\t      ShoutCast-style \"ICY\" responses</simpara>\n\t    </listitem>\n\t  </varlistentry>\n\t  <varlistentry>\n            <term><constant>NE_SESSFLAG_SSLv2</constant></term>\n\t    <listitem>\n\t      <simpara>this flag is ignored</simpara>\n\t    </listitem>\n\t  </varlistentry>\n\t  <varlistentry>\n            <term><constant>NE_SESSFLAG_RFC4918</constant> (default off)</term>\n\t    <listitem>\n\t      <simpara>enable this flag to enable support for\n\t      RFC4918-only WebDAV features; losing\n\t      backwards-compatibility with RFC2518 servers</simpara>\n\t    </listitem>\n\t  </varlistentry>\n\t  <varlistentry>\n            <term><constant>NE_SESSFLAG_CONNAUTH</constant> (default off)</term>\n\t    <listitem>\n\t      <simpara>enable this flag if an RFC-violating\n\t      connection-based HTTP authentication scheme is in\n\t      use</simpara>\n\t    </listitem>\n\t  </varlistentry>\n\t  <varlistentry>\n            <term><constant>NE_SESSFLAG_TLS_SNI</constant> (default on)</term>\n\t    <listitem>\n\t      <simpara>disable this flag if a server is used\n              which does not correctly support the TLS SNI \n              extension</simpara>\n\t    </listitem>\n\t  </varlistentry>\n\t  <varlistentry>\n            <term><constant>NE_SESSFLAG_EXPECT100</constant> (default off)</term>\n\t    <listitem>\n\t      <simpara>enable this flag to enable the request flag\n\t      <constant>NE_REQFLAG_EXPECT100</constant> for new\n\t      requests</simpara>\n\t    </listitem>\n\t  </varlistentry>\n\t  <varlistentry>\n            <term><constant>NE_SESSFLAG_SHAREPOINT</constant> (default off)</term>\n\t    <listitem>\n\t      <simpara>enable this flag to use various workarounds to\n\t      improve interoperability with SharePoint</simpara>\n\t    </listitem>\n\t  </varlistentry>\n\t  <varlistentry>\n            <term><constant>NE_SESSFLAG_STRICT</constant> (default on)</term>\n\t    <listitem>\n\t      <simpara>disable this flag to parse HTTP/1.1 messages\n\t      without strict requirements introduced in RFC 7230 and\n\t      later</simpara>\n\t    </listitem>\n\t  </varlistentry>\n        </variablelist>\n  </refsect1>\n\n  <refsect1>\n    <title>Return value</title>\n\n    <para>The <function>ne_get_session_flag</function> function\n    returns zero if a flag is disabled, less than zero if the flag is\n    not supported, or greater than zero if the flag is enabled.</para>\n  </refsect1>\n\n  <refsect1>\n    <title>See also</title>\n\n    <para><xref linkend=\"ne_session_create\"/>, <xref\n    linkend=\"ne_set_request_flag\"/>.</para>\n\n  </refsect1>\n\n</refentry>\n"
  },
  {
    "path": "doc/ref/shave.xml",
    "content": "    <refentry id=\"refshave\">\n\n      <refmeta>\n\t<refentrytitle>ne_shave</refentrytitle>\n\t<manvolnum>3</manvolnum>\n      </refmeta>\n\n      <refnamediv>\n\t<refname>ne_shave</refname>\n\t<refpurpose>trim whitespace from a string</refpurpose>\n      </refnamediv>\n      \n      <refsynopsisdiv>\n\t\n\t<funcsynopsis>\n\n\t  <funcsynopsisinfo>#include &lt;ne_string.h&gt;</funcsynopsisinfo>\n\n\t  <funcprototype>\n\t    <funcdef>char *<function>ne_shave</function></funcdef>\n\t    <paramdef>char *<parameter>str</parameter></paramdef>\n\t    <paramdef>const char *<parameter>whitespace</parameter></paramdef>\n\t  </funcprototype>\n\n\t</funcsynopsis>\n\t\n      </refsynopsisdiv>\n\n      <refsect1>\n\t<title>Description</title>\n\n\t<para><function>ne_shave</function> returns a portion of\n<parameter>str</parameter> with any leading or trailing characters in\nthe <parameter>whitespace</parameter> array removed.\n<parameter>str</parameter> may be modified.  Note that the return\nvalue may not be equal to <parameter>str</parameter>.</para>\n\n      </refsect1>\n\n      <refsect1>\n\t<title>Examples</title>\n\n\t<para>The following code segment will output\n\t<literal>\"fish\"</literal>:</para>\n\t\n\t<programlisting>char s[] = \".!.fish!.!\";\nputs(ne_shave(s, \".!\"));</programlisting>\n\n      </refsect1>\n\n    </refentry>\n\n"
  },
  {
    "path": "doc/ref/sockssl.xml",
    "content": "<refentry id=\"refsockssl\">\n\n  <refmeta>\n    <refentrytitle>ne_sock_handshake</refentrytitle>\n    <manvolnum>3</manvolnum>\n  </refmeta>\n\n  <refnamediv>\n    <refname id=\"ne_sock_handshake\">ne_sock_handshake</refname>\n    <refname id=\"ne_sock_sessid\">ne_sock_sessid</refname>\n    <refname id=\"ne_sock_cipher\">ne_sock_cipher</refname>\n    <refname id=\"ne_sock_getproto\">ne_sock_getproto</refname>\n    <refname id=\"ne_sock_getcert\">ne_sock_getcert</refname>\n    <refname id=\"ne_ssl_check_certificate\">ne_ssl_check_certificate</refname>\n    <refpurpose>SSL socket functions</refpurpose>\n  </refnamediv>\n  \n  <refsynopsisdiv>\n\n    <funcsynopsis>\n\n      <funcsynopsisinfo>#include &lt;ne_socket.h&gt;</funcsynopsisinfo>\n\n      <funcprototype>\n        <funcdef>int <function>ne_sock_handshake</function></funcdef>\n        <paramdef>ne_socket *<parameter>sock</parameter></paramdef>\n        <paramdef>ne_ssl_context *<parameter>ctx</parameter></paramdef>\n        <paramdef>const char *<parameter>hostname</parameter></paramdef>\n        <paramdef>unsigned int <parameter>flags</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>int <function>ne_sock_sessid</function></funcdef>\n        <paramdef>ne_socket *<parameter>sock</parameter></paramdef>\n        <paramdef>unsigned char *<parameter>buf</parameter></paramdef>\n        <paramdef>size_t *<parameter>buflen</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>char *<function>ne_sock_cipher</function></funcdef>\n        <paramdef>ne_socket *<parameter>sock</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>enum ne_ssl_protocol <function>ne_sock_getproto</function></funcdef>\n        <paramdef>ne_socket *<parameter>sock</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>ne_ssl_certificate *<function>ne_sock_getcert</function></funcdef>\n        <paramdef>ne_socket *<parameter>sock</parameter></paramdef>\n        <paramdef>ne_ssl_context *<parameter>ctx</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>int <function>ne_ssl_check_certificate</function></funcdef>\n        <paramdef>ne_ssl_context *<parameter>ctx</parameter></paramdef>\n        <paramdef>ne_socket *<parameter>sock</parameter></paramdef>\n        <paramdef>const char *<parameter>hostname</parameter></paramdef>\n        <paramdef>const ne_inet_addr *<parameter>address</parameter></paramdef>\n        <paramdef>const ne_ssl_certificate *<parameter>cert</parameter></paramdef>\n        <paramdef>unsigned int <parameter>flags</parameter></paramdef>\n        <paramdef>int *<parameter>failures</parameter></paramdef>\n      </funcprototype>\n\n    </funcsynopsis>\n    \n  </refsynopsisdiv>\n\n  <refsect1>\n    <title>Description</title>\n\n    <para>The <function>ne_sock_handshake</function> function initiates an\n    SSL handshake on socket <parameter>sock</parameter> using SSL context\n    <parameter>ctx</parameter>. If <parameter>hostname</parameter> is\n    non-&null;, it is used as the Server Name Indication (SNI) hint. The\n    <parameter>flags</parameter> parameter must be zero.</para>\n\n    <para>The <function>ne_sock_sessid</function> function retrieves the\n    session ID of the current SSL session. If <parameter>buf</parameter> is\n    non-&null;, on success, copies at most <literal>*buflen</literal> bytes\n    to <parameter>buf</parameter> and sets <literal>*buflen</literal> to the\n    exact number of bytes copied. If <parameter>buf</parameter> is &null;,\n    on success, sets <literal>*buflen</literal> to the length of the session\n    ID.</para>\n\n    <para>The <function>ne_sock_cipher</function> function returns a\n    human-readable name of the SSL/TLS cipher used for the connection, or\n    &null; if none. The format of this string is not intended to be fixed or\n    parseable, but is informational only. The return value is a\n    &nul;-terminated malloc-allocated string which must be freed by the\n    caller.</para>\n\n    <para>The <function>ne_sock_getproto</function> function returns the\n    SSL/TLS protocol version used for socket <parameter>sock</parameter>, or\n    <constant>NE_SSL_PROTO_UNSPEC</constant> if SSL/TLS is not in use for\n    the socket.</para>\n\n    <para>The <function>ne_sock_getcert</function> function returns the\n    server certificate for the socket.</para>\n\n    <para>The <function>ne_ssl_check_certificate</function> function checks\n    the identity of a server certificate against the hostname or address used\n    to establish the connection, following rules specified by <ulink\n    url=\"https://www.rfc-editor.org/rfc/rfc2818\">RFC 2818</ulink> and\n    <ulink\n    url=\"https://www.rfc-editor.org/rfc/rfc3280\">RFC 3280</ulink>. Either <parameter>hostname</parameter> or\n    <parameter>address</parameter> can be non-&null;; whichever was used to\n    identify the server when establishing the SSL connection. If both are\n    &null;, matching will fail but the <literal>*identity</literal> output\n    parameter will still be set. The <parameter>flags</parameter> parameter\n    must be zero. If verification fails, the failure reasons are stored in\n    <literal>*failures</literal> as a binary OR of\n    <constant>NE_SSL_*</constant> values.</para>\n\n  </refsect1>\n\n  <refsect1>\n    <title>Return value</title>\n\n    <para><function>ne_sock_handshake</function> returns zero on success,\n    or non-zero on error.</para>\n\n    <para><function>ne_sock_sessid</function> returns zero on success,\n    or non-zero on error.</para>\n\n    <para><function>ne_sock_cipher</function> returns a malloc-allocated\n    string on success which must be freed by the caller, or &null; if no\n    cipher is in use.</para>\n\n    <para><function>ne_sock_getproto</function> returns the SSL/TLS protocol\n    version, or <constant>NE_SSL_PROTO_UNSPEC</constant>.</para>\n\n    <para><function>ne_sock_getcert</function> returns the server certificate,\n    or &null; on error.</para>\n\n    <para><function>ne_ssl_check_certificate</function> returns zero if\n    the identity matches, 1 if the identity does not match, or less than\n    zero if the certificate had no identity.</para>\n\n  </refsect1>\n\n  <refsect1>\n    <title>History</title>\n\n    <para><function>ne_sock_getproto</function> is available in &neon;\n    0.34.0 and later. <function>ne_sock_handshake</function> and\n    <function>ne_sock_getcert</function> are available in &neon;\n    0.37.0 and later.</para>\n  </refsect1>\n\n  <refsect1>\n    <title>See also</title>\n\n    <para><xref linkend=\"ne_ssl_context_create\"/></para>\n  </refsect1>\n\n</refentry>\n"
  },
  {
    "path": "doc/ref/sslca.xml",
    "content": "    <refentry id=\"refsslca\">\n\n      <refmeta>\n\t<refentrytitle>ne_ssl_load_ca</refentrytitle>\n\t<manvolnum>3</manvolnum>\n      </refmeta>\n\n      <refnamediv>\n\t<refname id=\"ne_ssl_load_ca\">ne_ssl_load_ca</refname>\n\t<refname id=\"ne_ssl_load_default_ca\">ne_ssl_load_default_ca</refname>\n\t<refpurpose>load SSL Certificate Authorities</refpurpose>\n      </refnamediv>\n      \n      <refsynopsisdiv>\n\t\n\t<funcsynopsis>\n\n\t  <funcsynopsisinfo>#include &lt;ne_session.h&gt;</funcsynopsisinfo>\n\n\t  <funcprototype>\n\t    <funcdef>int <function>ne_ssl_load_ca</function></funcdef>\n\t    <paramdef>ne_session *<parameter>session</parameter></paramdef>\n\t    <paramdef>const char *<parameter>filename</parameter></paramdef>\n\t  </funcprototype>\n\n\t  <funcprototype>\n\t    <funcdef>int <function>ne_ssl_load_default_ca</function></funcdef>\n\t    <paramdef>ne_session *<parameter>session</parameter></paramdef>\n\t  </funcprototype>\n\n\t</funcsynopsis>\n\t\n      </refsynopsisdiv>\n\n      <refsect1>\n\t<title>Description</title>\n\n\t<para>To indicate that a given CA certificate is trusted by the user,\nthe certificate can be loaded using the <function>ne_ssl_load_ca</function>\nfunction.  The <parameter>filename</parameter> parameter given must specify\nthe location of a PEM-encoded CA certificate.</para>\n\n\t<para>The SSL library in use by neon may include a default set\nof CA certificates; calling the\n<function>ne_ssl_load_default_ca</function> function will indicate\nthat these CAs are trusted by the user.</para>\n\n\t<para>If no CA certificates are loaded, or the server presents\na certificate which is invalid in some way, then the certificate must\nbe manually verified (see <xref linkend=\"ne_ssl_set_verify\"/>), otherwise the\nconnection will fail.</para>\n\n      </refsect1>\n\n      <refsect1>\n\t<title>Return value</title>\n\n\t<para>Both <function>ne_ssl_load_ca</function> and\n<function>ne_ssl_load_default_ca</function> functions return\n<literal>0</literal> on success, or non-zero on failure.</para>\n\n      </refsect1>\n\n      <refsect1>\n\t<title>Examples</title>\n\n\t<para>Load the CA certificate stored in <filename>/path/to/cacert.pem</filename>:</para>\n\t<programlisting>&egsess;\n\nif (ne_ssl_load_ca(sess, \"/path/to/cacert.pem\")) {\n   printf(\"Could not load CA cert: %s\\n\", ne_get_error(sess));\n}</programlisting>\n      </refsect1>\n\n      <refsect1>\n\t<title>See also</title>\n\n\t<para><xref linkend=\"ne_get_error\"/>, <xref\n\tlinkend=\"ne_ssl_set_verify\"/></para> </refsect1>\n\n    </refentry>\n"
  },
  {
    "path": "doc/ref/sslcert.xml",
    "content": "<refentry id=\"refcert\">\n\n  <refmeta>\n    <refentrytitle>ne_ssl_cert_identity</refentrytitle>\n    <manvolnum>3</manvolnum>\n  </refmeta>\n\n  <refnamediv>\n    <refname id=\"ne_ssl_cert_identity\">ne_ssl_cert_identity</refname>\n    <refname id=\"ne_ssl_cert_signedby\">ne_ssl_cert_signedby</refname>\n    <refname id=\"ne_ssl_cert_issuer\">ne_ssl_cert_issuer</refname>\n    <refname id=\"ne_ssl_cert_subject\">ne_ssl_cert_subject</refname>\n    <refpurpose>functions to access certificate properties</refpurpose>\n  </refnamediv>\n  \n  <refsynopsisdiv>\n\n    <funcsynopsis>\n\n      <funcsynopsisinfo>#include &lt;ne_ssl.h&gt;</funcsynopsisinfo>\n\n      <funcprototype>\n        <funcdef>const char *<function>ne_ssl_cert_identity</function></funcdef>\n        <paramdef>const ne_ssl_certificate *<parameter>cert</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>const ne_ssl_certificate *<function>ne_ssl_cert_signedby</function></funcdef>\n        <paramdef>const ne_ssl_certificate *<parameter>cert</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>const ne_ssl_dname *<function>ne_ssl_cert_subject</function></funcdef>\n        <paramdef>const ne_ssl_certificate *<parameter>cert</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>const ne_ssl_dname *<function>ne_ssl_cert_issuer</function></funcdef>\n        <paramdef>const ne_ssl_certificate *<parameter>cert</parameter></paramdef>\n      </funcprototype>\n\n    </funcsynopsis>\n\n  </refsynopsisdiv>\n\n  <refsect1>\n    <title>Description</title>\n\n    <para>The function <function>ne_ssl_cert_identity</function>\n    retrieves the <quote>identity</quote> of a certificate; for an\n    SSL server certificate, this will be the hostname for which the\n    certificate was issued.  In PKI parlance, the identity is the\n    <emphasis>common name</emphasis> attribute of the distinguished name of\n    the certificate subject.</para>\n\n    <para>The functions <function>ne_ssl_cert_subject</function> and\n    <function>ne_ssl_cert_issuer</function> can be used to access the\n    objects representing the distinguished name of the subject and of\n    the issuer of a certificate, respectively.</para>\n\n    <para>If a certificate object is part of a certificate chain, then\n    <function>ne_ssl_cert_signedby</function> can be used to find the\n    certificate which signed a particular certificate. For a\n    self-signed certificate or a certificate for which the full chain\n    is not available, this function will return &null;.</para>\n\n  </refsect1>\n\n  <refsect1>\n    <title>Return value</title>\n\n    <para><function>ne_ssl_cert_issuer</function> and\n    <function>ne_ssl_cert_subject</function> are guaranteed to never\n    return &null;. <function>ne_ssl_cert_identity</function> may\n    return &null; if the certificate has no specific\n    <quote>identity</quote>. <function>ne_ssl_cert_signedby</function>\n    may return &null; as covered above.</para>\n  </refsect1>\n\n  <refsect1>\n    <title>Examples</title>\n\n    <para>The following function could be used to display information\n    about a given certificate:</para>\n\n    <programlisting>void dump_cert(const ne_ssl_certificate *cert) {\n  const char *id = ne_ssl_cert_identity(cert);\n  char *dn;\n\n  if (id) \n    printf(\"Certificate was issued for '%s'.\\n\", id);\n\n  dn = ne_ssl_readable_dname(ne_ssl_cert_subject(cert));\n  printf(\"Subject: %s\\n\", dn);\n  free(dn);\n\n  dn = ne_ssl_readable_dname(ne_ssl_cert_issuer(cert));\n  printf(\"Issuer: %s\\n\", dn);\n  free(dn);\n}</programlisting>\n\n  </refsect1>\n\n  <refsect1>\n    <title>See also</title>\n\n    <para><xref linkend=\"ne_ssl_cert_cmp\"/>, <xref linkend=\"ne_ssl_readable_dname\"/></para>\n  </refsect1>\n\n</refentry>\n\n"
  },
  {
    "path": "doc/ref/sslcert2.xml",
    "content": "<refentry id=\"refsslcert2\">\n\n  <refmeta>\n    <refentrytitle>ne_ssl_cert_cmp</refentrytitle>\n    <manvolnum>3</manvolnum>\n  </refmeta>\n\n  <refnamediv>\n    <refname id=\"ne_ssl_cert_cmp\">ne_ssl_cert_cmp</refname>\n    <refname id=\"ne_ssl_cert_free\">ne_ssl_cert_free</refname>\n    <refname id=\"ne_ssl_cert_digest\">ne_ssl_cert_digest</refname>\n    <refname id=\"ne_ssl_cert_hdigest\">ne_ssl_cert_hdigest</refname>\n    <refname id=\"ne_ssl_cert_validity\">ne_ssl_cert_validity</refname>\n    <refname id=\"ne_ssl_cert_validity_time\">ne_ssl_cert_validity_time</refname>\n    <refpurpose>functions to operate on certificate objects</refpurpose>\n  </refnamediv>\n  \n  <refsynopsisdiv>\n\n    <funcsynopsis>\n\n      <funcsynopsisinfo>#include &lt;ne_header.h&gt;</funcsynopsisinfo>\n\n      <funcprototype>\n        <funcdef>int <function>ne_ssl_cert_cmp</function></funcdef>\n        <paramdef>const ne_ssl_certificate *<parameter>c1</parameter></paramdef>\n        <paramdef>const ne_ssl_certificate *<parameter>c2</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>void <function>ne_ssl_cert_free</function></funcdef>\n        <paramdef>ne_ssl_certificate *<parameter>cert</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>int <function>ne_ssl_cert_digest</function></funcdef>\n        <paramdef>const ne_ssl_certificate *<parameter>c1</parameter></paramdef>\n        <paramdef>char *<parameter>digest</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>char *<function>ne_ssl_cert_hdigest</function></funcdef>\n        <paramdef>const ne_ssl_certificate *<parameter>c1</parameter></paramdef>\n        <paramdef>unsigned int <parameter>flags</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>void <function>ne_ssl_cert_validity_time</function></funcdef>\n        <paramdef>const ne_ssl_certificate *<parameter>cert</parameter></paramdef>\n        <paramdef>time_t *<parameter>from</parameter></paramdef>\n        <paramdef>time_t *<parameter>until</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>void <function>ne_ssl_cert_validity</function></funcdef>\n        <paramdef>const ne_ssl_certificate *<parameter>cert</parameter></paramdef>\n        <paramdef>char *<parameter>from</parameter></paramdef>\n        <paramdef>char *<parameter>until</parameter></paramdef>\n      </funcprototype>\n    </funcsynopsis>\n\n  </refsynopsisdiv>\n\n  <refsect1>\n    <title>Description</title>\n\n    <para>The <function>ne_ssl_cert_cmp</function> function can be\n    used to compare two certificate objects; it returns zero if they\n    refer to the same certificate, and non-zero otherwise.</para>\n\n    <para>The <function>ne_ssl_cert_free</function> function can be\n    used to destroy a certificate object when it is no longer\n    needed.</para>\n\n    <para>The <function>ne_ssl_cert_digest</function> function writes\n    a human-readable fingerprint as a NUL-terminated string to the\n    <parameter>digest</parameter> buffer provided, in the format\n    \"aa:bb...:ff\". The <parameter>digest</parameter> buffer must be at\n    least <literal>NE_SSL_DIGESTLEN</literal> bytes in length.</para>\n\n    <para>The <function>ne_ssl_cert_hdigest</function> function\n    returns a human-readable fingerprint for the certificate\n    object. The <parameter>flags</parameter> parameter specifies the\n    hash formatting options as if passed to <xref linkend=\"ne_strhash\"/>. The\n    returned string is malloc-allocated and must be freed after use.</para>\n\n    <para>The <function>ne_ssl_cert_validity_time</function> function\n    retrieves both the time from which the certificate is valid from\n    and until. Each time is returned through the\n    <parameter>from</parameter> and <parameter>until</parameter>\n    parameters, which are written as <literal>(time_t)-1</literal> if\n    either time cannot be represented as a <literal>time_t</literal>\n    value. The <function>ne_ssl_cert_validity</function> function\n    similarly writes the validity times to the string buffers\n    provided, using RFC 1123-style date formatting (not\n    localized). The output parameters must be at least\n    <literal>NE_SSL_VDATELEN</literal> bytes in length. Either\n    parameter can be passed as &null;.</para>\n  </refsect1>\n\n  <refsect1>\n    <title>Return value</title>\n\n    <para><function>ne_ssl_cert_cmp</function> returns 0 if the\n    certificates are the same, and non-zero otherwise.\n    <function>ne_ssl_cert_digest</function> returns 0 on success or\n    non-zero on error. The return value of\n    <function>ne_ssl_cert_hdigest</function> is a NUL-terminated\n    malloc-allocated string, or &null; if the hash cannot be\n    created.</para>\n\n  </refsect1>\n\n  <refsect1>\n    <title>History</title>\n\n    <para><function>ne_ssl_cert_hdigest</function> is available in\n    in &neon; 0.32.0 and later.</para>\n  </refsect1>\n\n  <refsect1>\n    <title>See also</title>\n\n    <para><xref linkend=\"ne_strhash\"/></para>\n  </refsect1>\n</refentry>\n\n"
  },
  {
    "path": "doc/ref/sslcertio.xml",
    "content": "<refentry id=\"refsslcertio\">\n\n  <refmeta>\n    <refentrytitle>ne_ssl_cert_read</refentrytitle>\n    <manvolnum>3</manvolnum>\n  </refmeta>\n\n  <refnamediv>\n    <refname id=\"ne_ssl_cert_read\">ne_ssl_cert_read</refname>\n    <refname id=\"ne_ssl_cert_write\">ne_ssl_cert_write</refname>\n    <refname id=\"ne_ssl_cert_import\">ne_ssl_cert_import</refname>\n    <refname id=\"ne_ssl_cert_export\">ne_ssl_cert_export</refname>\n    <refpurpose>functions to read or write certificates to and from files or strings</refpurpose>\n  </refnamediv>\n  \n  <refsynopsisdiv>\n\n    <funcsynopsis>\n\n      <funcsynopsisinfo>#include &lt;ne_ssl.h&gt;</funcsynopsisinfo>\n\n      <funcprototype>\n        <funcdef>ne_ssl_certificate *<function>ne_ssl_cert_read</function></funcdef>\n        <paramdef>const char *<parameter>filename</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>int <function>ne_ssl_cert_write</function></funcdef>\n        <paramdef>const ne_ssl_certificate *<parameter>cert</parameter></paramdef>\n        <paramdef>const char *<parameter>filename</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>ne_ssl_certificate *<function>ne_ssl_cert_import</function></funcdef>\n        <paramdef>const char *<parameter>data</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>char *<function>ne_ssl_cert_export</function></funcdef>\n        <paramdef>const ne_ssl_certificate *<parameter>cert</parameter></paramdef>\n      </funcprototype>\n\n    </funcsynopsis>\n\n  </refsynopsisdiv>\n\n  <refsect1>\n    <title>Description</title>\n\n    <para>The <function>ne_ssl_cert_write</function> function writes a\n    certificate to a file using the PEM encoding.  The\n    <function>ne_ssl_cert_export</function> function returns a\n    base64-encoded &nul;-terminated string representing the\n    certificate.  This string is malloc-allocated and should be\n    destroyed using <function>free</function> by the caller.</para>\n\n    <para>The <function>ne_ssl_cert_read</function> function reads a\n    certificate from a PEM-encoded file, and returns a certificate\n    object.  The <function>ne_ssl_cert_import</function> function\n    returns a certificate object from a base64-encoded string,\n    <parameter>data</parameter>, as returned by\n    <function>ne_ssl_cert_export</function>.  The certificate object\n    returned by these functions should be destroyed using <xref\n    linkend=\"ne_ssl_cert_free\"/> after use.</para>\n\n\n  </refsect1>\n\n  <refsect1>\n    <title>Return value</title>\n\n    <para><function>ne_ssl_cert_read</function> returns &null; if a\n    certificate could not be read from the file.\n    <function>ne_ssl_cert_write</function> returns non-zero if the\n    certificate could not be written to the file.\n    <function>ne_ssl_cert_export</function> always returns a\n    &nul;-terminated string, and never &null;.\n    <function>ne_ssl_cert_import</function> returns &null; if the\n    string was not a valid base64-encoded certificate.</para>\n\n  </refsect1>\n\n  <refsect1>\n    <title>Encoding Formats</title>\n\n    <para>The string produced by\n    <function>ne_ssl_cert_export</function> is the base64 encoding of\n    the DER representation of the certificate.  The file written by\n    <function>ne_ssl_cert_write</function> uses the PEM format: this\n    is the base64 encoding of the DER representation with newlines\n    every 64 characters, and start and end marker lines.</para>\n  </refsect1>\n\n</refentry>\n\n"
  },
  {
    "path": "doc/ref/sslctx.xml",
    "content": "<refentry id=\"refsslctx\">\n\n  <refmeta>\n    <refentrytitle>ne_ssl_context_create</refentrytitle>\n    <manvolnum>3</manvolnum>\n  </refmeta>\n\n  <refnamediv>\n    <refname id=\"ne_ssl_context_create\">ne_ssl_context_create</refname>\n    <refname id=\"ne_ssl_context_trustcert\">ne_ssl_context_trustcert</refname>\n    <refname id=\"ne_ssl_context_trustdefca\">ne_ssl_context_trustdefca</refname>\n    <refname id=\"ne_ssl_context_keypair\">ne_ssl_context_keypair</refname>\n    <refname id=\"ne_ssl_context_set_clicert\">ne_ssl_context_set_clicert</refname>\n    <refname id=\"ne_ssl_context_set_ccprovide\">ne_ssl_context_set_ccprovide</refname>\n    <refname id=\"ne_ssl_context_set_versions\">ne_ssl_context_set_versions</refname>\n    <refname id=\"ne_ssl_context_set_verify\">ne_ssl_context_set_verify</refname>\n    <refname id=\"ne_ssl_context_set_flag\">ne_ssl_context_set_flag</refname>\n    <refname id=\"ne_ssl_context_get_flag\">ne_ssl_context_get_flag</refname>\n    <refname id=\"ne_ssl_context_destroy\">ne_ssl_context_destroy</refname>\n    <refpurpose>SSL context management functions</refpurpose>\n  </refnamediv>\n  \n  <refsynopsisdiv>\n\n    <funcsynopsis>\n\n      <funcsynopsisinfo>#include &lt;ne_ssl.h&gt;</funcsynopsisinfo>\n\n      <funcprototype>\n        <funcdef>ne_ssl_context *<function>ne_ssl_context_create</function></funcdef>\n        <paramdef>int <parameter>mode</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>void <function>ne_ssl_context_trustcert</function></funcdef>\n        <paramdef>ne_ssl_context *<parameter>ctx</parameter></paramdef>\n        <paramdef>const ne_ssl_certificate *<parameter>cert</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>void <function>ne_ssl_context_trustdefca</function></funcdef>\n        <paramdef>ne_ssl_context *<parameter>ctx</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>int <function>ne_ssl_context_keypair</function></funcdef>\n        <paramdef>ne_ssl_context *<parameter>ctx</parameter></paramdef>\n        <paramdef>const char *<parameter>cert</parameter></paramdef>\n        <paramdef>const char *<parameter>key</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>void <function>ne_ssl_context_set_clicert</function></funcdef>\n        <paramdef>ne_ssl_context *<parameter>ctx</parameter></paramdef>\n        <paramdef>const ne_ssl_client_cert *<parameter>cc</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>void <function>ne_ssl_context_set_ccprovide</function></funcdef>\n        <paramdef>ne_ssl_context *<parameter>ctx</parameter></paramdef>\n        <paramdef>ne_ssl_ccprovide_fn <parameter>provider</parameter></paramdef>\n        <paramdef>void *<parameter>userdata</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>int <function>ne_ssl_context_set_versions</function></funcdef>\n        <paramdef>ne_ssl_context *<parameter>ctx</parameter></paramdef>\n        <paramdef>enum ne_ssl_protocol <parameter>min</parameter></paramdef>\n        <paramdef>enum ne_ssl_protocol <parameter>max</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>int <function>ne_ssl_context_set_verify</function></funcdef>\n        <paramdef>ne_ssl_context *<parameter>ctx</parameter></paramdef>\n        <paramdef>int <parameter>required</parameter></paramdef>\n        <paramdef>const char *<parameter>ca_names</parameter></paramdef>\n        <paramdef>const char *<parameter>verify_cas</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>void <function>ne_ssl_context_set_flag</function></funcdef>\n        <paramdef>ne_ssl_context *<parameter>ctx</parameter></paramdef>\n        <paramdef>int <parameter>flag</parameter></paramdef>\n        <paramdef>int <parameter>value</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>int <function>ne_ssl_context_get_flag</function></funcdef>\n        <paramdef>ne_ssl_context *<parameter>ctx</parameter></paramdef>\n        <paramdef>int <parameter>flag</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>void <function>ne_ssl_context_destroy</function></funcdef>\n        <paramdef>ne_ssl_context *<parameter>ctx</parameter></paramdef>\n      </funcprototype>\n\n    </funcsynopsis>\n    \n  </refsynopsisdiv>\n\n  <refsect1>\n    <title>Description</title>\n\n    <para>The <function>ne_ssl_context_create</function> function creates\n    an SSL context object. The <parameter>mode</parameter> parameter should\n    be <constant>NE_SSL_CTX_CLIENT</constant> for a client context,\n    <constant>NE_SSL_CTX_SERVER</constant> for a server context.</para>\n\n    <para>For a client context, the <function>ne_ssl_context_trustcert</function>\n    function configures the context to trust the certificate\n    <parameter>cert</parameter>. The <function>ne_ssl_context_trustdefca</function>\n    function configures the context to trust the default system certificate\n    authorities.</para>\n\n    <para>For a server context, the <function>ne_ssl_context_keypair</function>\n    function configures the server certificate and private key. The\n    <parameter>cert</parameter> and <parameter>key</parameter> parameters are\n    filenames to PEM-encoded certificates.</para>\n\n    <para>The <function>ne_ssl_context_set_clicert</function> function\n    configures a client certificate for a client context. The client\n    certificate <parameter>cc</parameter> must be in the decrypted state. The\n    certificate object is duplicated internally and may be destroyed by the\n    caller after the function returns.</para>\n\n    <para>The <function>ne_ssl_context_set_ccprovide</function> function\n    registers a callback to provide a client certificate on demand if\n    requested by the server. The <parameter>provider</parameter> callback\n    is passed the <parameter>userdata</parameter> pointer, an array of\n    acceptable CA distinguished names, and the count of names in the\n    array.</para>\n\n    <para>The <function>ne_ssl_context_set_versions</function> function\n    sets the minimum and maximum SSL/TLS protocol versions allowed for\n    the connection. This must be called before initiating the SSL handshake.</para>\n\n    <para>For a server context, the <function>ne_ssl_context_set_verify</function>\n    function configures client certificate verification. If\n    <parameter>required</parameter> is non-zero, a client certificate is\n    required. If <parameter>ca_names</parameter> is non-&null;, it specifies\n    a filename containing PEM certificates from which CA names are sent in\n    the client certificate request. The <parameter>verify_cas</parameter>\n    parameter specifies CAs used for verification.</para>\n\n    <para>The <function>ne_ssl_context_set_flag</function> function\n    sets a flag for the SSL context. The\n    <function>ne_ssl_context_get_flag</function> function retrieves\n    the current value of a flag. No flags are currently\n    defined.</para>\n\n    <para>The <function>ne_ssl_context_destroy</function> function destroys\n    an SSL context object and frees all associated resources.</para>\n\n  </refsect1>\n\n  <refsect1>\n    <title>Return value</title>\n\n    <para><function>ne_ssl_context_create</function> returns an SSL context\n    object, or &null; on error.</para>\n\n    <para><function>ne_ssl_context_keypair</function>,\n    <function>ne_ssl_context_set_versions</function>, and\n    <function>ne_ssl_context_set_verify</function> return zero on success,\n    or non-zero on error.</para>\n\n    <para><function>ne_ssl_context_get_flag</function> returns the flag\n    value.</para>\n\n  </refsect1>\n\n  <refsect1>\n    <title>History</title>\n\n    <para><function>ne_ssl_context_set_clicert</function> and\n    <function>ne_ssl_context_trustdefca</function> are available in\n    &neon; 0.37.0 and later.</para>\n  </refsect1>\n\n  <refsect1>\n    <title>See also</title>\n\n    <para><xref linkend=\"ne_sock_handshake\"/></para>\n  </refsect1>\n\n</refentry>\n"
  },
  {
    "path": "doc/ref/ssldname.xml",
    "content": "\n    <refentry id=\"refssldname\">\n\n      <refmeta>\n\t<refentrytitle>ne_ssl_dname</refentrytitle>\n\t<manvolnum>3</manvolnum>\n      </refmeta>\n\n      <refnamediv>\n\t<refname id=\"ne_ssl_readable_dname\">ne_ssl_readable_dname</refname>\n        <refname id=\"ne_ssl_dname_cmp\">ne_ssl_dname_cmp</refname>\n\t<refpurpose>SSL distinguished name handling</refpurpose>\n      </refnamediv>\n      \n      <refsynopsisdiv>\n\t\n\t<funcsynopsis>\n\n\t  <funcsynopsisinfo>#include &lt;ne_ssl.h&gt;</funcsynopsisinfo>\n\n\t  <funcprototype>\n\t    <funcdef>const char *<function>ne_ssl_readable_dname</function></funcdef>\n\t    <paramdef>const ne_ssl_dname *<parameter>dname</parameter></paramdef>\n\t  </funcprototype>\n\n\t  <funcprototype>\n\t    <funcdef>int <function>ne_ssl_dname_cmp</function></funcdef>\n\t    <paramdef>const ne_ssl_dname *<parameter>dn1</parameter></paramdef>\n\t    <paramdef>const ne_ssl_dname *<parameter>dn2</parameter></paramdef>\n\t  </funcprototype>\n\n\t</funcsynopsis>\n\t\n      </refsynopsisdiv>\n\n      <refsect1>\n\t<title>Description</title>\n\n\t<para>The <function>ne_ssl_readable_dname</function> function\ncreates a single-line, human-readable string out of an\n<type>ne_ssl_dname</type> object.  The returned string is\n<function>malloc</function>()-allocated, and must be\n<function>free</function>()d by the caller.</para>\n\n\t<para>The <function>ne_ssl_dname_cmp</function> function\n\tcompares two distinguished names, and returns zero if they are\n\tequal, or non-zero otherwise.</para>\n\n      </refsect1>\n\n      <refsect1>\n\t<title>Return value</title>\n\n\t<para><function>ne_ssl_readable_dname</function> returns a <function>malloc</function>-allocated\n        string, and never &null;.</para>\n\n      </refsect1>\n\n      <refsect1>\n\t<title>Examples</title>\n\n        <para>See <xref linkend=\"ne_ssl_cert_subject\"/> for an example\n        use of <function>ne_ssl_readable_dname</function>.</para>\n\n      </refsect1>\n\n      <refsect1>\n\t<title>See also</title>\n\n\t<para><xref linkend=\"ne_ssl_cert_subject\"/></para>\n      </refsect1>\n\n    </refentry>\n"
  },
  {
    "path": "doc/ref/sslproto.xml",
    "content": "<refentry id=\"refsslproto\">\n\n  <refmeta>\n    <refentrytitle>ne_ssl_proto_name</refentrytitle>\n    <manvolnum>3</manvolnum>\n  </refmeta>\n\n  <refnamediv>\n    <refname id=\"ne_ssl_proto_name\">ne_ssl_proto_name</refname>\n    <refpurpose>SSL/TLS protocol version to name mapping</refpurpose>\n  </refnamediv>\n  \n  <refsynopsisdiv>\n\n    <funcsynopsis>\n\n      <funcsynopsisinfo>#include &lt;ne_ssl.h&gt;</funcsynopsisinfo>\n\n      <funcprototype>\n        <funcdef>const char *<function>ne_ssl_proto_name</function></funcdef>\n        <paramdef>enum ne_ssl_protocol <parameter>proto</parameter></paramdef>\n      </funcprototype>\n\n    </funcsynopsis>\n\n  </refsynopsisdiv>\n\n  <refsect1>\n    <title>Description</title>\n\n    <para>The <function>ne_ssl_proto_name</function> function returns\n    a human-readable name for a SSL/TLS version constant. The set of\n    versions currently are as follows:</para>\n\n    <variablelist>\n      <varlistentry>\n        <term><constant>NE_SSL_PROTO_UNSPEC</constant></term>\n\t<listitem><simpara>unspecified/unknown version</simpara></listitem>\n      </varlistentry>\n      <varlistentry>\n        <term><constant>NE_SSL_PROTO_SSL3</constant></term>\n\t<listitem><simpara>SSL v3</simpara></listitem>\n      </varlistentry>\n      <varlistentry>\n        <term><constant>NE_SSL_PROTO_TLS_1_0</constant></term>\n\t<listitem><simpara>TLS v1.0</simpara></listitem>\n      </varlistentry>\n      <varlistentry>\n        <term><constant>NE_SSL_PROTO_TLS_1_1</constant></term>\n\t<listitem><simpara>TLS v1.1</simpara></listitem>\n      </varlistentry>\n      <varlistentry>\n        <term><constant>NE_SSL_PROTO_TLS_1_2</constant></term>\n\t<listitem><simpara>TLS v1.2</simpara></listitem>\n      </varlistentry>\n      <varlistentry>\n        <term><constant>NE_SSL_PROTO_TLS_1_3</constant></term>\n\t<listitem><simpara>TLS v1.3</simpara></listitem>\n      </varlistentry>\n    </variablelist>\n\n  </refsect1>\n\n  <refsect1>\n    <title>Return value</title>\n\n    <para>The <function>ne_ssl_proto_name</function> function always\n    returns a non-&null; string even if the version constant is not\n    valid.</para>\n\n  </refsect1>\n\n  <refsect1>\n    <title>History</title>\n\n    <para><function>ne_ssl_proto_name</function> is available in\n    &neon; 0.34.0 and later.</para>\n  </refsect1>\n\n  <refsect1>\n    <title>See also</title>\n\n    <para><xref linkend=\"ne_ssl_set_protovers\"/></para>\n\n  </refsect1>\n\n</refentry>\n"
  },
  {
    "path": "doc/ref/ssltrust.xml",
    "content": "    <refentry id=\"refsslca\">\n\n      <refmeta>\n\t<refentrytitle>ne_ssl_trust_cert</refentrytitle>\n\t<manvolnum>3</manvolnum>\n      </refmeta>\n\n      <refnamediv>\n\t<refname id=\"ne_ssl_trust_cert\">ne_ssl_trust_cert</refname>\n\t<refname id=\"ne_ssl_trust_default_ca\">ne_ssl_trust_default_ca</refname>\n\t<refpurpose>functions to indicate that certificates are trusted</refpurpose>\n      </refnamediv>\n      \n      <refsynopsisdiv>\n\t\n\t<funcsynopsis>\n\n\t  <funcsynopsisinfo>#include &lt;ne_session.h&gt;</funcsynopsisinfo>\n\n\t  <funcprototype>\n\t    <funcdef>void <function>ne_ssl_trust_cert</function></funcdef>\n\t    <paramdef>ne_session *<parameter>session</parameter></paramdef>\n\t    <paramdef>const ne_ssl_certificate *<parameter>cert</parameter></paramdef>\n\t  </funcprototype>\n\n\t  <funcprototype>\n\t    <funcdef>void <function>ne_ssl_trust_default_ca</function></funcdef>\n\t    <paramdef>ne_session *<parameter>session</parameter></paramdef>\n\t  </funcprototype>\n\n\t</funcsynopsis>\n\t\n      </refsynopsisdiv>\n\n      <refsect1>\n\t<title>Description</title>\n\n\t<para>To indicate that a given certificate is trusted by the\nuser, the certificate object can be passed to\n<function>ne_ssl_trust_cert</function>.  The certificate object is\nduplicated internally and can subsequently be destroyed.</para>\n\n\t<para>The SSL library in use by &neon; may include a default\nset of CA certificates; calling the\n<function>ne_ssl_trust_default_ca</function> function will indicate\nthat these CAs are trusted by the user.</para>\n\n      </refsect1>\n\n      <refsect1>\n\t<title>Examples</title>\n\n\t<para>Load the CA certificate stored in <filename>/path/to/cacert.pem</filename>:</para>\n\t<programlisting>&egsess;\nne_ssl_certificate *cert = ne_ssl_cert_read(\"/path/to/cacert.pem\");\n\nif (cert) {\n   ne_ssl_trust_cert(sess, cert);\n   ne_ssl_cert_free(cert);\n} else {\n   printf(\"Could not load CA cert: %s\\n\", ne_get_error(sess));\n}</programlisting>\n      </refsect1>\n\n      <refsect1>\n\t<title>History</title>\n\n        <para><function>ne_ssl_trust_default_ca</function> is not safe\n        to call for non-SSL sessions versions of &neon; before\n        0.33.0. In 0.33.0 and later, this function is a no-op for\n        non-SSL sessions.</para>\n      </refsect1>\n      \n      <refsect1>\n\t<title>See also</title>\n\n\t<para><xref linkend=\"ne_session_create\"/>, <xref linkend=\"ne_ssl_cert_read\"/>, <xref\n\tlinkend=\"ne_ssl_cert_import\"/>, <xref\n\tlinkend=\"ne_ssl_cert_free\"/></para> </refsect1>\n\n    </refentry>\n"
  },
  {
    "path": "doc/ref/sslvers.xml",
    "content": "<refentry id=\"refsslvers\">\n\n  <refmeta>\n    <refentrytitle>ne_ssl_set_protovers</refentrytitle>\n    <manvolnum>3</manvolnum>\n  </refmeta>\n\n  <refnamediv>\n    <refname id=\"ne_ssl_set_protovers\">ne_ssl_set_protovers</refname>\n    <refpurpose>set session SSL/TLS minimum or maximum protocol version</refpurpose>\n  </refnamediv>\n  \n  <refsynopsisdiv>\n\n    <funcsynopsis>\n\n      <funcsynopsisinfo>#include &lt;ne_session.h&gt;</funcsynopsisinfo>\n\n      <funcprototype>\n        <funcdef>int <function>ne_ssl_set_protovers</function></funcdef>\n        <paramdef>ne_session *<parameter>sess</parameter></paramdef>\n        <paramdef>enum ne_ssl_protocol <parameter>min</parameter></paramdef>\n        <paramdef>enum ne_ssl_protocol <parameter>max</parameter></paramdef>\n      </funcprototype>\n\n    </funcsynopsis>\n\n  </refsynopsisdiv>\n\n  <refsect1>\n    <title>Description</title>\n\n    <para>The <function>ne_ssl_set_protovers</function> function sets\n    the minimum and/or maximum SSL/TLS version. Either minimum and/or\n    maximum may be specified as\n    <constant>NE_SSL_PROTO_UNSPEC</constant>, in which case no limit\n    is imposed.</para>\n\n  </refsect1>\n\n  <refsect1>\n    <title>Return value</title>\n\n    <para>The <function>ne_ssl_set_protovers</function> function\n    returns zero on success or non-zero on error. Errors include an\n    invalid range (minimum above maximum), or if the protocol version\n    is not supported by the SSL/TLS toolkit in use, or if SSL/TLS is\n    not in use for the session.</para>\n\n  </refsect1>\n\n  <refsect1>\n    <title>History</title>\n\n    <para><function>ne_ssl_set_protovers</function> is available in\n    &neon; 0.34.0 and later.</para>\n  </refsect1>\n\n  <refsect1>\n    <title>See also</title>\n\n    <para><xref linkend=\"ne_ssl_proto_name\"/>, <xref\n    linkend=\"ne_session_create\"/>.</para>\n  </refsect1>\n</refentry>\n"
  },
  {
    "path": "doc/ref/sslvfy.xml",
    "content": "    <refentry id=\"refsslvfy\"> <!-- -*- xml-mode -*- -->\n\n      <refmeta>\n\t<refentrytitle>ne_ssl_set_verify</refentrytitle>\n\t<manvolnum>3</manvolnum>\n      </refmeta>\n\n      <refnamediv>\n\t<refname id=\"ne_ssl_set_verify\">ne_ssl_set_verify</refname>\n\t<refpurpose>register an SSL certificate verification callback</refpurpose>\n      </refnamediv>\n      \n      <refsynopsisdiv>\n\t\n\t<funcsynopsis>\n\n\t  <funcsynopsisinfo>#include &lt;ne_session.h&gt;</funcsynopsisinfo>\n\n\t  <!-- hard to put data type declarations here -->\n\n\t  <funcprototype>\n\t    <funcdef>typedef int <function>ne_ssl_verify_fn</function></funcdef>\n\t    <paramdef>void *<parameter>userdata</parameter></paramdef>\n\t    <paramdef>int <parameter>failures</parameter></paramdef>\n\t    <paramdef>const ne_ssl_certificate *<parameter>cert</parameter></paramdef>\n\t  </funcprototype>\n\n\t  <funcprototype>\n\t    <funcdef>void <function>ne_ssl_set_verify</function></funcdef>\n\t    <paramdef>ne_session *<parameter>session</parameter></paramdef>\n\t    <paramdef>ne_ssl_verify_fn <parameter>verify_fn</parameter></paramdef>\n\t    <paramdef>void *<parameter>userdata</parameter></paramdef>\n\t  </funcprototype>\n\n\t</funcsynopsis>\n\t\n      </refsynopsisdiv>\n\n      <refsect1>\n\t<title>Description</title>\n\n\t<para>To enable manual SSL certificate verification, a\ncallback can be registered using\n<function>ne_ssl_set_verify</function>.  If such a callback is not\nregistered, when a connection is established to an SSL server which\ndoes not present a certificate signed by a trusted CA (see <xref\nlinkend=\"ne_ssl_trust_cert\"/>), or if the certificate presented is invalid in\nsome way, the connection will fail.</para>\n\n\t<para>When the callback is invoked, the\n<parameter>failures</parameter> parameter gives a bitmask indicating\nin what way the automatic certificate verification failed.  The value\nis equal to the bit-wise OR of one or more of the following\nconstants (and is guaranteed to be non-zero):</para>\n\n\t<variablelist>\n\t  <varlistentry><term><constant>NE_SSL_NOTYETVALID</constant></term>\n\t    <listitem>\n\t      <simpara>The certificate is not yet valid.</simpara>\n\t    </listitem>\n\t  </varlistentry>\n\t  <varlistentry><term><constant>NE_SSL_EXPIRED</constant></term>\n\t    <listitem>\n\t      <simpara>The certificate has expired.</simpara>\n\t    </listitem>\n\t  </varlistentry>\n\t  <varlistentry><term><constant>NE_SSL_IDMISMATCH</constant></term>\n\t    <listitem>\n\t      <simpara>The hostname used for the session does not match\nthe hostname to which the certificate was issued.</simpara>\n\t    </listitem>\n\t  </varlistentry>\n\t  <varlistentry><term><constant>NE_SSL_UNTRUSTED</constant></term>\n\t    <listitem>\n\t      <simpara>The Certificate Authority which signed the certificate\nis not trusted.</simpara>\n\t    </listitem>\n\t  </varlistentry>\n\t</variablelist>\n\n\t<para>Note that if either of the\n\t<constant>NE_SSL_IDMISMATCH</constant> or\n\t<constant>NE_SSL_UNTRUSTED</constant> failures is given, the\n\tconnection may have been intercepted by a third party, and\n\tmust not be presumed to be <quote>secure</quote>.</para>\n\n\t<para>The <parameter>cert</parameter> parameter passed to the\ncallback represents the certificate which was presented by the server.\nIf the server presented a chain of certificates, the chain can be\naccessed using <xref linkend=\"ne_ssl_cert_signedby\"/>.  The\n<parameter>cert</parameter> object given is not valid after the\ncallback returns.</para>\n\n      </refsect1>\n\n      <refsect1>\n\t<title>Return value</title>\n\n\t<para>The verification callback must return zero to indicate\nthat the certificate should be trusted; and non-zero otherwise (in\nwhich case, the connection will fail).</para>\n      </refsect1>\n\n      <refsect1>\n\t<title>Examples</title>\n\n\t<para>The following code implements an example verification\n\tcallback, using the <function>dump_cert</function> function\n\tfrom <xref linkend=\"ne_ssl_cert_subject\"/> to display\n\tcertification information.  Notice that the hostname of the\n\tserver used for the session is passed as the\n\t<parameter>userdata</parameter> parameter to the\n\tcallback.</para>\n\n\t<programlisting>\nstatic int\nmy_verify(void *userdata, int failures, const ne_ssl_certificate *cert)\n{\n  const char *hostname = userdata;\n\n  dump_cert(cert);\n\n  puts(\"Certificate verification failed - the connection may have been \"\n       \"intercepted by a third party!\");\n\n  if (failures &amp; NE_SSL_IDMISMATCH) { \n    const char *id = ne_ssl_cert_identity(cert);\n    if (id) \n      printf(\"Server certificate was issued to '%s' not '%s'.\\n\",\n             id, hostname);\n    else\n      printf(\"The certificate was not issued for '%s'\\n\", hostname);\n  }\n\n  if (failures &amp; NE_SSL_UNTRUSTED)\n    puts(\"The certificate is not signed by a trusted Certificate Authority.\");\n\n  /* ... check for validity failures ... */\n\n  if (prompt_user())\n    return 1; /* fail verification */\n  else\n    return 0; /* trust the certificate anyway */\n}\n\nint\nmain(...)\n{\n  ne_session *sess = ne_session_create(\"https\", \"some.host.name\", 443);\n  ne_ssl_set_verify(sess, my_verify, \"some.host.name\");\n  ...\n}</programlisting>\n\n      </refsect1>\n\n      <refsect1>\n\t<title>See also</title>\n\n\t<para><xref linkend=\"ne_ssl_trust_cert\"/>, <xref\n\tlinkend=\"ne_ssl_readable_dname\"/>, <xref linkend=\"ne_ssl_cert_subject\"/></para>\n      </refsect1>\n\n   </refentry>\n"
  },
  {
    "path": "doc/ref/status.xml",
    "content": "    <refentry id=\"refstatus\">\n\n      <refmeta>\n\t<refentrytitle>ne_status</refentrytitle>\n\t<manvolnum>3</manvolnum>\n      </refmeta>\n\n      <refnamediv>\n\t<refname id=\"ne_status\">ne_status</refname>\n\t<refpurpose>HTTP status structure</refpurpose>\n      </refnamediv>\n      \n      <refsynopsisdiv>\n\t\n\t<funcsynopsis><funcsynopsisinfo>#include &lt;ne_utils.h&gt;\n\ntypedef struct {\n    int major_version;\n    int minor_version;\n    int code;\n    int klass;\n    char *reason_phrase;\n} <type>ne_status</type>;</funcsynopsisinfo></funcsynopsis>\n\t\n      </refsynopsisdiv>\n\n      <refsect1>\n\t<title>Description</title>\n\n\t<para>The <type>ne_status</type> type represents an HTTP\n\tresponse status; used in response messages giving a result of\n\trequest.  The <structfield>major_version</structfield> and\n\t<structfield>minor_version</structfield> fields give the\n\tprotocol version supported by the server issuing the response.\n\tThe <structfield>code</structfield> field gives the status\n\tcode of the result (lying between <literal>100</literal> and\n\t<literal>599</literal> inclusive), and the\n\t<structfield>klass</structfield> field gives the class, which\n\tis equal to the most significant digit of the status. The\n\t<structfield>reason_phrase</structfield> field gives a\n\thuman-readable string describing the status, which is purely\n\tinformational (and optional) - any interpretation of the\n\tresponse status must be done using the\n\t<structfield>klass</structfield> and/or\n\t<structfield>code</structfield> fields.</para>\n\n\t<para>There are five classes of response status code defined\n\tfor HTTP/1.1 (see <ulink\n\turl=\"https://www.rfc-editor.org/rfc/rfc9110#name-status-codes\">RFC\n\t9110 §15</ulink>):</para>\n\t\n\t<variablelist>\n\t  <varlistentry>\n\t    <term><literal>1xx</literal></term>\n\t    <listitem><simpara>Informational response.</simpara></listitem>\n\t  </varlistentry>\n\n\t  <varlistentry>\n\t    <term><literal>2xx</literal></term>\n\t    <listitem><simpara>Success: the operation was successful</simpara></listitem>\n\t  </varlistentry>\n\n\t  <varlistentry>\n\t    <term><literal>3xx</literal></term>\n\t    <listitem><simpara>Redirection</simpara></listitem>\n\t  </varlistentry>\n\n\t  <varlistentry>\n\t    <term><literal>4xx</literal></term> <listitem><simpara>Client\n\t    error: the request made was incorrect in some\n\t    manner.</simpara></listitem>\n\t  </varlistentry>\n\n\t  <varlistentry>\n\t    <term><literal>5xx</literal></term>\n\t    <listitem><simpara>Server error</simpara></listitem>\n\t  </varlistentry>\n\t</variablelist>\n\n      </refsect1>\n\n      <refsect1> <title>Notes</title> <para>The\n      <structfield>klass</structfield> field is named\n      <quote>klass</quote> not <quote>class</quote> so that the header\n      can be used from a C++ program, in which <quote>class</quote> is\n      a reserved word.</para></refsect1>\n\n      <refsect1> <title>See also</title> <para><xref\nlinkend=\"ne_get_status\"/>.</para> </refsect1>\n\n    </refentry>\n"
  },
  {
    "path": "doc/ref/tok.xml",
    "content": "    <refentry id=\"reftok\">\n\n      <refmeta>\n\t<refentrytitle>ne_token</refentrytitle>\n\t<manvolnum>3</manvolnum>\n      </refmeta>\n\n      <refnamediv>\n\t<refname>ne_token</refname>\n\t<refname>ne_qtoken</refname>\n\t<refpurpose>string tokenizers</refpurpose>\n      </refnamediv>\n      \n      <refsynopsisdiv>\n\t\n\t<funcsynopsis>\n\n\t  <funcsynopsisinfo>#include &lt;ne_string.h&gt;</funcsynopsisinfo>\n\n\t  <funcprototype>\n\t    <funcdef>char *<function>ne_token</function></funcdef>\n\t    <paramdef>char **<parameter>str</parameter></paramdef>\n\t    <paramdef>char <parameter>sep</parameter></paramdef>\n\t  </funcprototype>\n\n\t  <funcprototype>\n\t    <funcdef>char *<function>ne_qtoken</function></funcdef>\n\t    <paramdef>char **<parameter>str</parameter></paramdef>\n\t    <paramdef>char <parameter>sep</parameter></paramdef>\n\t    <paramdef>const char *<parameter>quotes</parameter></paramdef>\n\t  </funcprototype>\n\n\t</funcsynopsis>\n\t\n      </refsynopsisdiv>\n\n      <refsect1>\n\t<title>Description</title>\n\n\t<!-- FIXME: italics on tokenize -->\n\n\t<para><function>ne_token</function> and\n<function>ne_qtoken</function> tokenize the string at the location\nstored in the pointer <parameter>str</parameter>.  Each time the\nfunction is called, it returns the next token, and modifies the\n<parameter>str</parameter> pointer to point to the remainder of the\nstring, or &null; if there are no more tokens in the string.  A token\nis delimited by the separator character <parameter>sep</parameter>; if\n<function>ne_qtoken</function> is used any quoted segments of the\nstring are skipped when searching for a separator.  A quoted segment\nis enclosed in a pair of one of the characters given in the\n<parameter>quotes</parameter> string.</para>\n\n\t<para>The string being tokenized is modified each time\nthe tokenizing function is called; replacing the next separator\ncharacter with a &nul; terminator.</para>\n\n      </refsect1>\n\n      <refsect1>\n\t<title>Examples</title>\n\n\t<para>The following function prints out each token in a\ncomma-separated string <parameter>list</parameter>, which is\nmodified in-place:</para>\n\n\t<programlisting>static void splitter(char *list)\n{\n  do {\n    printf(\"Token: %s\\n\", ne_token(&amp;list, ','));\n  while (list);\n}</programlisting>\n\n </refsect1>\n\n    </refentry>\n"
  },
  {
    "path": "doc/ref/vers.xml",
    "content": "<refentry id=\"refvers\">\n\n  <refmeta>\n    <refentrytitle>ne_version_match</refentrytitle>\n    <manvolnum>3</manvolnum>\n  </refmeta>\n\n  <refnamediv>\n    <refname>ne_version_match</refname>\n    <refname>ne_version_string</refname>\n    <refname>ne_version_library</refname>\n    <refpurpose>library versioning</refpurpose>\n  </refnamediv>\n\n  <refsynopsisdiv>\n\n    <funcsynopsis>\n\n      <funcsynopsisinfo>#include &lt;ne_utils.h&gt;</funcsynopsisinfo>\n\n      <funcprototype>\n        <funcdef>int <function>ne_version_match</function></funcdef>\n        <paramdef>int <parameter>major</parameter></paramdef>\n        <paramdef>int <parameter>minor</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>const char *<function>ne_version_string</function></funcdef>\n\t<void/>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>const char *<function>ne_version_library</function></funcdef>\n\t<void/>\n      </funcprototype>\n\n    </funcsynopsis>\n\n  </refsynopsisdiv>\n\n  <refsect1>\n    <title>Description</title>\n\n    <para>The <function>ne_version_match</function> function returns\n    zero if the library version is backwards-compatible with the\n    version given in the <parameter>major</parameter> and\n    <parameter>minor</parameter> parameters.</para>\n\n    <para>The <function>ne_version_string</function> function returns\n    a string giving the library version and build information.</para>\n\n    <para>The <function>ne_version_library</function> function returns\n    a string giving the library version number alone, for example\n    <literal>\"0.37.0\"</literal>.</para>\n\n  </refsect1>\n\n  <refsect1>\n    <title>Examples</title>\n\n    <para>To require a version of &neon; which is backwards-compatible with version 1.2.0:</para>\n\n    <programlisting>if (ne_version_match(1, 2)) {\n    printf(\"Library version out of date: 1.2 required, found %s.\",\n           ne_version_string());\n    exit(1);\n}</programlisting>\n\n  </refsect1>\n\n  <refsect1>\n    <title>History</title>\n\n    <para>The <function>ne_version_library</function> function is available in\n    &neon; 0.37.0 and later.</para>\n\n  </refsect1>\n\n</refentry>\n"
  },
  {
    "path": "doc/ref/xml.xml",
    "content": "<refentry id=\"refxml\">\n\n  <refmeta>\n    <refentrytitle>ne_xml_create</refentrytitle>\n    <manvolnum>3</manvolnum>\n  </refmeta>\n\n  <refnamediv>\n    <refname id=\"ne_xml_create\">ne_xml_create</refname>\n    <refname id=\"ne_xml_destroy\">ne_xml_destroy</refname>\n    <refpurpose>create and destroy an XML parser</refpurpose>\n  </refnamediv>\n  \n  <refsynopsisdiv>\n\n    <funcsynopsis>\n\n      <funcsynopsisinfo>#include &lt;ne_xml.h&gt;</funcsynopsisinfo>\n\n      <funcprototype>\n        <funcdef>ne_xml_parser *<function>ne_xml_create</function></funcdef>\n        <void/>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>void <function>ne_xml_destroy</function></funcdef>\n        <paramdef>ne_xml_parser *<parameter>parser</parameter></paramdef>\n      </funcprototype>\n\n    </funcsynopsis>\n\n  </refsynopsisdiv>\n\n  <refsect1>\n    <title>Description</title>\n\n    <para>The <function>ne_xml_create</function> function creates an\n    XML parser object, which can be used for parsing XML documents\n    using stacked SAX handlers.</para>\n\n  </refsect1>\n\n  <refsect1>\n    <title>Return value</title>\n\n    <para><function>ne_xml_create</function> returns a pointer to an\n    XML parser object, and never &null;</para> </refsect1>\n\n  <refsect1>\n    <title>See also</title>\n\n    <para><xref linkend=\"ne_xml_parse_response\"/></para>\n  </refsect1>\n\n</refentry>\n\n"
  },
  {
    "path": "doc/ref/xmlreq.xml",
    "content": "<refentry id=\"refxmlreq\">\n\n  <refmeta>\n    <refentrytitle>ne_xml_parse_response</refentrytitle>\n    <manvolnum>3</manvolnum>\n  </refmeta>\n\n  <refnamediv>\n    <refname id=\"ne_xml_parse_response\">ne_xml_parse_response</refname>\n    <refname id=\"ne_xml_dispatch_request\">ne_xml_dispatch_request</refname>\n    <refname id=\"ne_xml_dispatchif_request\">ne_xml_dispatchif_request</refname>\n    <refpurpose>helper functions for parsing XML responses</refpurpose>\n  </refnamediv>\n\n  <refsynopsisdiv>\n\n    <funcsynopsis>\n\n      <funcsynopsisinfo>#include &lt;ne_xmlreq.h&gt;</funcsynopsisinfo>\n\n      <funcprototype>\n        <funcdef>int <function>ne_xml_parse_response</function></funcdef>\n        <paramdef>ne_request *<parameter>req</parameter></paramdef>\n        <paramdef>ne_xml_parser *<parameter>parser</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>int <function>ne_xml_dispatch_request</function></funcdef>\n        <paramdef>ne_request *<parameter>req</parameter></paramdef>\n        <paramdef>ne_xml_parser *<parameter>parser</parameter></paramdef>\n      </funcprototype>\n\n      <funcprototype>\n        <funcdef>int <function>ne_xml_dispatchif_request</function></funcdef>\n        <paramdef>ne_request *<parameter>req</parameter></paramdef>\n        <paramdef>ne_xml_parser *<parameter>parser</parameter></paramdef>\n        <paramdef>ne_accept_response <parameter>acceptor</parameter></paramdef>\n        <paramdef>void *<parameter>userdata</parameter></paramdef>\n      </funcprototype>\n\n    </funcsynopsis>\n\n  </refsynopsisdiv>\n\n  <refsect1>\n    <title>Description</title>\n\n    <para>The <function>ne_xml_parse_response</function> function\n    reads an HTTP response body and processes it using the given XML\n    parser. The function must be called\n    <function>ne_begin_request</function> has returned successfully\n    for the request, and then invokes\n    <function>ne_read_response_block</function> until the entire\n    response body has been read. On successful return,\n    <function>ne_end_request</function> must be called to finalise\n    response processing.</para>\n\n    <para>The <function>ne_xml_dispatch_request</function> and\n    <function>ne_xml_dispatchif_request</function> functions is\n    equivalent to calling <xref linkend=\"ne_request_dispatch\"/> to\n    dispatch an HTTP request and process the response, parsing the\n    response body using the given XML parser under certain conditions:\n\n    <itemizedlist>\n      <listitem><simpara>For\n      <function>ne_xml_dispatch_request</function>, any\n      <literal>2xx</literal> class response with an XML\n      content-type.</simpara></listitem>\n\n      <listitem><simpara>For\n      <function>ne_xml_dispatchif_request</function>, if the\n      <parameter>acceptor</parameter> callback returns non-zero,\n      and the response uses an XML content-type.</simpara></listitem>\n    </itemizedlist>\n\n    In both cases, the rules in <ulink\n    url=\"https://www.rfc-editor.org/rfc/rfc7303\">RFC 7303</ulink> are\n    followed to identify XML content-types, that is\n    <literal>text/xml</literal>, <literal>application/xml</literal>,\n    or any other content-type ending in a <literal>+xml</literal>\n    suffix. The <parameter>userdata</parameter> parameter is passed to\n    the <parameter>acceptor</parameter> function.</para>\n\n    <para>For all three functions:\n\n    <itemizedlist>\n      <listitem><simpara>the XML parser is invoked repeatedly until\n      the end of the document is reached.</simpara></listitem>\n\n      <listitem><simpara>if an error occurs during XML parsing, the\n      session error string is set to describe the parse error, and the\n      connection is terminated without continuing to process the\n      response..</simpara></listitem>\n    </itemizedlist>\n\n    </para>\n\n  </refsect1>\n\n  <refsect1>\n    <title>Return value</title>\n\n    <para>All functions documented here return zero on success, or an\n    <xref linkend=\"error-codes\"/> on failure.</para></refsect1>\n\n  <refsect1>\n    <title>History</title>\n\n    <para><function>ne_xml_dispatchif_request</function> is available\n    in &neon; 0.36.0 and later.</para>\n  </refsect1>\n\n  <refsect1>\n    <title>See also</title>\n\n    <para><xref linkend=\"ne_xml_create\"/>, <xref linkend=\"ne_request_dispatch\"/></para>\n  </refsect1>\n\n</refentry>\n"
  },
  {
    "path": "doc/refentry.xml",
    "content": "<refentry id=\"refXXXX\">\n\n  <refmeta>\n    <refentrytitle>ne_foo</refentrytitle>\n    <manvolnum>3</manvolnum>\n  </refmeta>\n\n  <refnamediv>\n    <refname id=\"ne_foo\">ne_foo</refname>\n    <refname id=\"ne_bar\">ne_bar</refname>\n    <refpurpose>functions which do foo and bar</refpurpose>\n  </refnamediv>\n  \n  <refsynopsisdiv>\n\n    <funcsynopsis>\n\n      <funcsynopsisinfo>#include &lt;ne_header.h&gt;</funcsynopsisinfo>\n\n      <funcprototype>\n        <funcdef>void <function>ne_set_useragent</function></funcdef>\n        <paramdef>ne_session *<parameter>session</parameter></paramdef>\n        <paramdef>const char *<parameter>product</parameter></paramdef>\n      </funcprototype>\n\n    </funcsynopsis>\n\n  </refsynopsisdiv>\n\n  <refsect1>\n    <title>Description</title>\n\n    <para>XXX</para>\n\n  </refsect1>\n\n  <refsect1>\n    <title>Return value</title>\n\n    <para>XXX</para>\n  </refsect1>\n\n  <refsect1>\n    <title>Examples</title>\n\n    <para>XXX</para>\n  </refsect1>\n\n  <refsect1>\n    <title>See also</title>\n\n    <para>XXX</para>\n  </refsect1>\n\n</refentry>\n\n"
  },
  {
    "path": "doc/security.xml",
    "content": "<sect1 id=\"security\">\n  \n  <title>HTTP Client Security</title>\n\n  <para>&neon; is intended to be secure against a specific threat\n  model: use of a malicious HTTP server.  Under this threat model, a\n  range of attacks are possible against a client when the user (or\n  application) can be tricked into accessing an HTTP server which is\n  controlled by an attacker.  This section documents various types of\n  possible attack and describes what mitigation is used in\n  &neon;.</para>\n\n  <sect2>\n    <title>CPU or memory consumption attacks</title>\n\n    <para>&neon; uses fixed resource limits to prevent the following\n    attacks:</para>\n\n    <itemizedlist>\n      <listitem>\n        <para>memory/CPU consumption attack using an unbounded number\n        of response header fields</para>\n      </listitem>\n\n      <listitem>\n        <para>memory consumption attack using an unbounded length of\n        individual response header lines (or continuation\n        headers)</para>\n      </listitem>\n      \n      <listitem>\n        <para>memory consumption attack against the PROPFIND code\n        using an unbounded number of properties (propstat elements)\n        per resource</para>\n      </listitem>\n\n      <listitem>\n        <para>memory consumption attack against the PROPFIND code\n        using an unbounded CDATA element in a \"flat property\"\n        value</para>\n      </listitem>\n    </itemizedlist>\n\n    <para>Memory consumption attacks against applications based on\n    &neon; by use of unbounded response length are also possible, but\n    must be mitigated at application level.  Memory consumption in\n    &neon; while reading response bodies is fixed and is not\n    proportional to the response length.</para>\n\n    <para>Test cases for all the above attacks are present in the\n    &neon; test suite.</para>\n\n  </sect2>\n\n  <sect2>\n    <title>SSL/TLS connection security</title>\n    \n    <para>When using a connection secured by SSL/TLS, it is necessary\n    for clients to verify that the X.509 certificate presented by the\n    server matches the server's expected identity.  The algorithm\n    required for this purpose is described in <ulink url=\"https://www.rfc-editor.org/rfc/rfc9110\">RFC 9110</ulink> and <ulink url=\"https://www.rfc-editor.org/rfc/rfc9110\">RFC 6125</ulink>,\n    and is implemented by &neon; in the following manner:</para>\n    \n    <orderedlist>\n      <listitem>\n        <para>the <literal>host</literal> argument passed to <xref\n        linkend=\"ne_session_create\"/> is the expected identity of the\n        server</para>\n      </listitem>\n      \n      <listitem>\n        <para>if the <parameter>host</parameter> argument is an IP\n        literal (e.g. <literal>\"198.51.100.42\"</literal> or\n        <literal>\"[2001:db8::42]\"</literal>), it is compared\n        <emphasis>only</emphasis> to any\n        <emphasis>iPAddress</emphasis> subjectAltName values\n        present</para>\n      </listitem>\n\n      <listitem>\n        <para>otherwise, the <parameter>host</parameter> parameter is\n        treated as a DNS hostname, and is compared with any\n        <emphasis>dNSName</emphasis> subjectAltName values if present;\n        if none match the hostname is compared with the most specific\n        commonName attribute in the Subject name.</para>\n      </listitem>\n    </orderedlist>\n    \n    <para>In the case where a server certificate is presented that\n    does not match the expected identity (or is otherwise not\n    trusted), &neon; will fail the request by default.  This behaviour\n    can be overridden by the use of a callback installed using <xref\n    linkend=\"ne_ssl_set_verify\"/>, which allows the application to\n    present the certificate details to a user for manual/off-line\n    verification, if possible.</para>\n  \n    <para>Test cases for the correctness of the implementation of the\n    identity verification algorithm are present in the &neon; test\n    suite.</para>\n\n  </sect2>\n\n  <sect2>\n    <title>Control character insertion in error messages</title>\n    \n    <para>Where error messages (as returned by\n    (<xref linkend=\"ne_get_error\"/>) contain data supplied by the\n    server, the untrusted data is sanitised to remove both control\n    characters and non-ASCII characters.  This prevents any attacks\n    where such error messages are exposed to the user and can\n    potentially distort the presentation of the interface (for\n    example, through the use of a carriage return character in a text\n    user interface).</para>\n  </sect2>\n\n  <sect2>\n    <title>Attacks against authentication credentials</title>\n    \n    <para>Authentication credentials can be compromised by a\n    \"downgrade attack\" by an active attacker; for example, where a\n    MITM presents a Basic authentication challenge in place of the\n    server's Digest challenge.  &neon; mitigates these attacks by\n    allowing the application (and hence, user) to specify that only a\n    specific set of authentication protocols is permitted.</para>\n\n    <para>When using Basic authentication, &neon; applies the scoping\n    rules from <ulink\n    url=\"https://www.rfc-editor.org/rfc/rfc7617.html#section-2.2\">RFC\n    7617 Section 2.2</ulink> to limit reuse of cached credentials\n    within a session.</para>\n\n    <para>&neon; supports the Digest and Negotiate authentication\n    schemes, which both allow authentication of users without passing\n    credentials in cleartext over the wire.</para>\n\n    <para>When using Digest authentication, &neon; uses hash algorithm\n    implementations from the configured SSL/TLS toolkit where\n    possible, or falls back to a bundled MD5 implementation where\n    SSL/TLS is not supported. If available, the SSL/TLS toolkit is\n    also used to generate random <literal>cnonce</literal> values.\n    The <literal>userhash</literal> field is supported for username\n    privacy (this depends on server-side enablement). The full range\n    of hash algorithms specified in <ulink\n    url=\"https://www.rfc-editor.org/rfc/rfc7616.html#section-6.1\">RFC\n    7616 Section 6.1</ulink> is supported if configured using OpenSSL\n    1.1.0 or later.</para>\n\n  </sect2>\n</sect1>\n"
  },
  {
    "path": "doc/ssl.xml",
    "content": "<sect1 id=\"ssl\"> <!-- -*- xml -*- -->\n\n <title>Secure connections: HTTP over SSL</title>\n\n <para>This section gives an introduction to SSL.  The text is\n inspired by <xref linkend=\"bib.ssltls\"/>.</para>\n\n <para>&neon; supports the use of HTTP over SSL<footnote id=\"foot.ssl.term\"><para>The\nterm <quote>SSL</quote> is used throughout this section to refer in\ngeneral to both the SSL protocol developed by Netscape and its\nsuccessor TLS, as adopted by the IETF.</para></footnote> to implement\n<firstterm>secure connections</firstterm>.  A secure connection in\nthis context means a connection which has\n<emphasis>integrity</emphasis>, <emphasis>secrecy</emphasis> and is\n<emphasis>authenticated</emphasis>.  Applications must go to some\neffort to correctly support secure connections&mdash;an application\nbased on &neon; does not magically become <quote>secure</quote> simply\nby flicking a switch and enabling the use of SSL.</para>\n\n<!-- SSL: integrity, secrecy, authentication. -->\n\n<!-- what is a certificate -->\n\n</sect1>\n"
  },
  {
    "path": "doc/using.xml",
    "content": "    <sect1 id=\"using\">\n      <title>How to use neon from your application</title>\n\n      <para>This section describes how to add &neon; support to an\n      application.  If you just want to quickly try out &neon;, use\n      the <xref linkend=\"refconfig\"/> script.</para>\n\n      <para>The &neon; source code is designed to be easily embedded\n      into an application source tree.  &neon; has no dependencies on\n      libraries other than an SSL toolkit and XML parser, though the\n      source tree can be configured to have no support for SSL or XML\n      if desired.  To configure the &neon; source code some <ulink\n      url=\"http://www.gnu.org/software/autoconf/\">GNU autoconf</ulink>\n      macros are supplied, which can be used in a number of ways, as\n      follows:</para>\n      \n      <itemizedlist>\n\t<listitem>\n\t  \n\t  <para>autoconf macros are distributed in the 'macros'\n\t  subdirectory of the neon distribution.  Use the NEON_LIBRARY\n\t  macro from your configure.in to check for the presence of\n\t  the neon library installed on the system.  The macro adds an\n\t  '--with-neon=...'  argument to configure, which allows the\n\t  user to specify a location for the library (the standard\n\t  /usr and /usr/local directories are checked automatically\n\t  without having to be specified).</para></listitem>\n\t  \n\t  <listitem><para>The 'src' directory of the neon package can be\n\t  imported directly into your application, if you do not wish\n\t  to add an external dependency.  If you wish to bundle, use\n\t  the NEON_BUNDLED macro to configure neon in your application:\n\t  here, the neon sources are bundled in a directory called\n\t  'libneon':</para>\n\t  \n\t  <programlisting>NEON_BUNDLED(libneon, ...)</programlisting>\n\t  \n\t  <para>If your application supports builds where srcdir != builddir,\n\t  you should use the NEON_VPATH_BUNDLED macro like this:</para>\n\t  \n\t  <programlisting>NEON_VPATH_BUNDLED(${srcdir}/libneon, libneon, ...)</programlisting>\n\t  \n\t  <para>If you use this macro, a '--with-included-neon' option\n\t  will be added to the generated configure script.  This\n\t  allows the user to force the bundled neon to be used in the\n\t  application, rather than any neon library found on the\n\t  system. If you allow neon to be configured this way, you\n\t  must also configure an XML parser. Use the NEON_XML_PARSER\n\t  macro to do this.</para></listitem>\n\t  \n\t  <listitem><para>The final argument to the _BUNDLED macros is a\n\t  set of actions which are executed if the bundled build *is*\n\t  chosen (rather than an external neon which might have been\n\t  found on the user's system).  In here, use either the\n\t  NEON_LIBTOOL_BUILD or NEON_NORMAL_BUILD macro to set up the\n\t  neon Makefile appropriately: including adding the neon source\n\t  directory to the recursive make.</para></listitem>\n\t  \n\t</itemizedlist>\n\t\n\t<para>A full fragment might be:</para>\n\t\n<programlisting>NEON_BUNDLED(libneon, [\n  NEON_NORMAL_BUILD\n  NEON_XML_PARSER\n  SUBDIRS=\"libneon $SUBDIRS\"\n])</programlisting>\n\t\n\t<para>This means the bundled neon source directory (called 'libneon')\n\tis used if no neon is found on the system, and the standard XML\n\tparser search is used.</para>\n\t\n      </sect1>\n\n      <sect1 id=\"example\">\n        <title>Example application</title>\n\n\t<para>The code below is a simple example which sends a\n\t<literal>PUT</literal> request, using the API from\n\t<literal>&lt;ne_basic.h&gt;</literal>:\n\n<programlisting><![CDATA[\n#include <stdio.h>\n#include <stdlib.h>\n\n#include <ne_basic.h>\n\nstatic const char data[] = \"Example data.\\n\";\n\nint main(int argc, char **argv)\n{\n    ne_session *sess;\n    int ec = EXIT_SUCCESS;\n\n    ne_sock_init(); /* Global library initialization. */\n\n    sess = ne_session_create(\"http\", \"localhost\", 80);\n\n    if (ne_putbuf(sess, \"/dav/data.txt\", data, sizeof data)) {\n        fprintf(stderr, \"PUT Request failed: %s\\n\", ne_get_error(sess));\n        ec = EXIT_FAILURE;\n    }\n\n    ne_session_destroy(sess);\n\n    return ec;\n}\n]]></programlisting></para></sect1>\n      \n      <sect1 id=\"compliance\">\n\t<title>Standards compliance</title>\n\t\n\t<para>&neon; is intended to be compliant with the IETF and W3C\n\tstandards which it implements, with a few exceptions due to\n\tpractical necessity or interoperability issues.  These\n\texceptions are documented in this section.</para>\n\n\t<sect2><title>RFC 2518, HTTP Extensions for Distributed Authoring&mdash;WebDAV</title>\n\t\n\t<para>&neon; is deliberately not compliant with section\n\t23.4.2, and treats property names as a (namespace-URI, name)\n\tpair.  This is <ulink\n\turl=\"http://lists.w3.org/Archives/Public/w3c-dist-auth/1999OctDec/0343.html\">generally\n\tconsidered</ulink> to be correct behaviour by the WebDAV\n\tworking group, and is likely to formally adopted in a future\n\trevision of the specification.</para></sect2>\n\t\n        <sect2><title>RFC 2616, Hypertext Transfer Protocol&mdash;HTTP/1.1</title>\n        \n        <para>There is some confusion in this specification about the\n        use of the <quote>identity</quote>\n        <firstterm>transfer-coding</firstterm>.  &neon; ignores the\n        <literal>Transfer-Encoding</literal> response header if it\n        contains only the (now deprecated) <quote>identity</quote>\n        token, and will determine the response message length as if\n        the header was not present.  &neon; will give an error if a\n        response includes a <literal>Transfer-Encoding</literal>\n        header with a value other than <quote>identity</quote> or\n        <quote>chunked</quote>.</para></sect2>\n\n        <sect2>\n        <title><ulink url=\"https://datatracker.ietf.org/doc/html/rfc3986\">RFC 3986</ulink> Uniform Resource Identifier (URI): Generic Syntax and <ulink url=\"https://datatracker.ietf.org/doc/html/rfc6874\">RFC 6874</ulink>, Representing IPv6 Zone Identifiers in Address Literals and Uniform Resource Identifiers</title>\n\n        <para>&neon; parses and handles scoped IPv6 link-local literal\n        addresses passed to <xref linkend=\"refsess\"/> since version\n        <literal>0.34</literal>, following the syntax in RFC 6874. An\n        example <literal>host</literal> argument would be\n        <literal>\"[fe80::cafe%25eth0]\"</literal> where\n        <literal>\"eth0\"</literal> is the scope ID. Since <ulink\n        url=\"https://datatracker.ietf.org/doc/html/rfc9110\">RFC\n        9110</ulink> does not reference the extended syntax of scoped\n        IPv6 literals, and a scope ID has no meaningful interpretation\n        outside of the client host, it is omitted from the\n        <literal>Host</literal> header sent over the wire. So the\n        example argument here translates to an HTTP/1.1 header field\n        of <literal>Host: [fe80::cafe]</literal>.</para>\n        </sect2>\n\n        <sect2>\n        <title>RFC 7616, HTTP Digest Access Authentication</title>\n\n        <para>&neon; is not strictly compliant with the quoting rules\n        given in the grammar for the <literal>Authorization</literal>\n        header.  The grammar requires that the <literal>qop</literal>\n        and <literal>algorithm</literal> parameters are not quoted,\n        however one widely deployed server implementation\n        (Microsoft&reg; IIS 5) rejects the request if these parameters\n        are not quoted.  &neon; sends these parameters with\n        quotes&mdash;this is not known to cause any problems with\n        other server implementations.</para>\n\n        <para>RFC 7616 predates RFC 9112 and uses conflicting language\n        around URIs. &neon; uses the RFC 9112\n        <literal>request-target</literal> in both the\n        <literal>A2</literal> grammar and the <literal>uri=</literal>\n        parameter of the <literal>Authorization</literal>\n        header. &neon; will accept (and resolve) any URI-reference in\n        the <literal>domain=</literal> parameter for\n        <literal>WWW-Authenticate</literal> response header\n        field.</para>\n\n        </sect2>\n\n\t<sect2>\n        <title>Namespaces in XML</title>\n\n        <para>The &neon; XML parser interface will accept and parse\n        without error some XML documents which are well-formed\n        according to the XML specification but do not conform to the\n        \"Namespaces in XML\" specification <xref\n        linkend=\"bib.xmlnames\"/>.  Specifically: the restrictions on\n        the first character of the <literal>NCName</literal> rule are\n        not all implemented; &neon; will allow any\n        <literal>CombiningChar</literal>, <literal>Extender</literal>\n        and some characters from the <literal>Digit</literal> class in\n        this position.</para> </sect2>\n \n        <!-- a few RFC2818/3280 issues: rules about when to cache\n        sessions in the face of unclean shutdown are strict, neon is\n        probably not compliant: document or fix.  Likewise SSL\n        shutdown issues in general.  Cert hostname checks allow\n        wildcard \"*.\" syntax which is less than 2818 but more than\n        3280 requires. -->\n\n    </sect1>\n"
  },
  {
    "path": "doc/xml.xml",
    "content": "<!-- neon XML interface -*- text -*- -->\n\n<sect1 id=\"xml\">\n\n  <title>Parsing XML</title>\n\n  <para>The &neon; XML interface is exposed by the\n  <filename>ne_xml.h</filename> header file.  This interface gives a\n  wrapper around the standard <ulink\n  url=\"http://www.saxproject.org/\">SAX</ulink> API used by XML\n  parsers, with an additional abstraction, <firstterm>stacked SAX\n  handlers</firstterm>, and also giving consistent <ulink\n  url=\"http://www.w3.org/TR/REC-xml-names\">XML Namespace</ulink> support.</para>\n\n<sect2 id=\"xml-sax\">\n  <title>Introduction to SAX</title>\n\n  <para>A SAX-based parser works by emitting a sequence of\n  <firstterm>events</firstterm> to reflect the tokens being parsed\n  from the XML document.  For example, parsing the following document\n  fragment:\n\n<programlisting><![CDATA[\n<hello>world</hello>\n]]></programlisting>\n\n  results in the following events:\n\n  <orderedlist>\n    <listitem>\n      <simpara>&startelm; \"hello\"</simpara>\n    </listitem>\n    <listitem>\n      <simpara>&cdata; \"world\"</simpara>\n    </listitem>\n    <listitem>\n      <simpara>&endelm; \"hello\"</simpara>\n    </listitem>\n  </orderedlist>\n\n  This example demonstrates the three event types used used in the\n  subset of SAX exposed by the &neon; XML interface: &startelm;,\n  &cdata; and &endelm;.  In a C API, an <quote>event</quote> is\n  implemented as a function callback; three callback types are used in\n  &neon;, one for each type of event.</para>\n\n</sect2>\n\n<sect2 id=\"xml-stacked\">\n  <title>Stacked SAX handlers</title>\n\n  <para>WebDAV property values are represented as fragments of XML,\n  transmitted as parts of larger XML documents over HTTP (notably in\n  the body of the response to a <literal>PROPFIND</literal> request).\n  When &neon; parses such documents, the SAX events generated for\n  these property value fragments may need to be handled by the\n  application, since &neon; has no knowledge of the structure of\n  properties used by the application.</para>\n\n  <para>To solve this problem<footnote id=\"foot.xml.sax\"><para>This\n  <quote>problem</quote> only needs solving because the SAX interface\n  is so inflexible when implemented as C function callbacks; a better\n  approach would be to use an XML parser interface which is not based\n  on callbacks.</para></footnote> the &neon; XML interface introduces\n  the concept of a <firstterm>SAX handler</firstterm>.  A SAX handler\n  comprises a &startelm;, &cdata; and &endelm; callback; the\n  &startelm; callback being defined such that each handler may\n  <emphasis>accept</emphasis> or <emphasis>decline</emphasis> the\n  &startelm; event.  Handlers are composed into a <firstterm>handler\n  stack</firstterm> before parsing a document.  When a new &startelm;\n  event is generated by the XML parser, &neon; invokes each &startelm;\n  callback in the handler stack in turn until one accepts the event.\n  The handler which accepts the event will then be subsequently be\n  passed &cdata; events if the element contains character data,\n  followed by an &endelm; event when the element is closed.  If no\n  handler in the stack accepts a &startelm; event, the branch of the\n  tree is ignored.</para>\n\n  <para>To illustrate, given a handler A, which accepts the\n  <literal>cat</literal> and <literal>age</literal> elements, and a\n  handler B, which accepts the <literal>name</literal> element, the\n  following document:\n\n<example id=\"xml-example\">\n<title>An example XML document</title>\n<programlisting><![CDATA[\n<cat>\n  <age>3</age>    \n  <name>Bob</name>\n</cat>\n]]></programlisting></example>\n\n  would be parsed as follows:\n  \n  <orderedlist>\n    <listitem>\n      <simpara>A &startelm; \"cat\" &rarr; <emphasis>accept</emphasis></simpara>\n    </listitem>\n    <listitem>\n      <simpara>A &startelm; \"age\" &rarr; <emphasis>accept</emphasis></simpara>\n    </listitem>\n    <listitem>\n      <simpara>A &cdata; \"3\"</simpara>\n    </listitem>\n    <listitem>\n      <simpara>A &endelm; \"age\"</simpara>\n    </listitem>\n    <listitem>\n      <simpara>A &startelm; \"name\" &rarr; <emphasis>decline</emphasis></simpara>\n    </listitem>\n    <listitem>\n      <simpara>B &startelm; \"name\" &rarr; <emphasis>accept</emphasis></simpara>\n    </listitem>\n    <listitem>\n      <simpara>B &cdata; \"Bob\"</simpara>\n    </listitem>\n    <listitem>\n      <simpara>B &endelm; \"name\"</simpara>\n    </listitem>\n    <listitem>\n      <simpara>A &endelm; \"cat\"</simpara>\n    </listitem>\n  </orderedlist></para>\n\n  <para>The search for a handler which will accept a &startelm; event\n  begins at the handler of the parent element and continues toward the\n  top of the stack.  For the root element, it begins at the base of\n  the stack.  In the above example, handler A is at the base, and\n  handler B at the top; if the <literal>name</literal> element had any\n  children, only B's &startelm; would be invoked to accept\n  them.</para>\n\n</sect2>\n\n<sect2 id=\"xml-state\">\n  <title>Maintaining state</title>\n\n  <para>To facilitate communication between independent handlers, a\n  <firstterm>state integer</firstterm> is associated with each element\n  being parsed.  This integer is returned by &startelm; callback and\n  is passed to the subsequent &cdata; and &endelm; callbacks\n  associated with the element.  The state integer of the parent\n  element is also passed to each &startelm; callback, the value zero\n  used for the root element (which by definition has no\n  parent).</para>\n\n  <para>To further extend <xref linkend=\"xml-example\"/>: if handler A\n  defines that the state of the root element <sgmltag>cat</sgmltag>\n  will be <literal>42</literal>, the event trace would be as\n  follows:\n\n  <orderedlist>\n    <listitem>\n      <simpara>A &startelm; (parent = 0, \"cat\") &rarr;\n      <emphasis>accept</emphasis>, state = 42\n      </simpara>\n    </listitem>\n    <listitem>\n      <simpara>A &startelm; (parent = 42, \"age\") &rarr; \n      <emphasis>accept</emphasis>, state = 50\n      </simpara>\n    </listitem>\n    <listitem>\n      <simpara>A &cdata; (state = 50, \"3\")</simpara>\n    </listitem>\n    <listitem>\n      <simpara>A &endelm; (state = 50, \"age\")</simpara>\n    </listitem>\n    <listitem>\n      <simpara>A &startelm; (parent = 42, \"name\") &rarr; \n      <emphasis>decline</emphasis></simpara>\n    </listitem>\n    <listitem>\n      <simpara>B &startelm; (parent = 42, \"name\") &rarr;\n      <emphasis>accept</emphasis>, state = 99</simpara>\n    </listitem>\n    <listitem>\n      <simpara>B &cdata; (state = 99, \"Bob\")</simpara>\n    </listitem>\n    <listitem>\n      <simpara>B &endelm; (state = 99, \"name\")</simpara>\n    </listitem>\n    <listitem>\n      <simpara>A &endelm; (state = 42, \"cat\")</simpara>\n    </listitem>\n  </orderedlist></para>\n\n  <para>To avoid collisions between state integers used by different\n  handlers, the interface definition of any handler includes the range\n  of integers it will use.</para>\n\n</sect2>\n\n<sect2 id=\"xml-ns\">\n  <title>XML namespaces</title>\n\n  <para>To support XML namespaces, every element name is represented\n  as a <emphasis>(namespace, name)</emphasis> pair.  The &startelm;\n  and &endelm; callbacks are passed namespace and name strings\n  accordingly.  If an element in the XML document has no declared\n  namespace, the namespace given will be the empty string,\n  <literal>\"\"</literal>.</para>\n\n</sect2>\n\n</sect1>\n"
  },
  {
    "path": "macros/.gitignore",
    "content": ""
  },
  {
    "path": "macros/ChangeLog",
    "content": "Sun Sep 12 18:38:13 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NEON_USE_EXTERNAL): Check for IDNA, LFS, SOCKS\n\tsupport.\n\t(NEON_SOCKS): Use common feature code for SOCKSv5 support.\n\nFri Sep 10 20:52:54 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (LIBNEON_SOURCE_CHECKS): Safer autoheader template for\n\tdeclaring stpcpy as necessary for bundled neon builds.\n\t(NEON_WARNINGS): Drop -Winline.\n\nWed Aug 25 19:44:26 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (LIBNEON_SOURCE_CHECKS): Check for poll.\n\nSat Jul  3 11:39:01 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (LIBNEON_SOURCE_CHECKS): Pick up gethostbyname in\n\t-lsocket for QNX.\n\nFri Apr 16 11:43:10 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon-xml-parser.m4 (NEON_XML_PARSER): If built using libtool,\n\tand --with-expat specifies a libexpat.la file, add the libexpat.la\n\tto NEON_LTLIBS.\n\n\t* neon.m4 (NEON_COMMON_CHECKS): Substitute NEON_LTLIBS.\n\nTue Apr 13 20:51:59 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NEON_GSSAPI): Check for presence of\n\tgssapi/gssapi_generic.h.\n\nWed Apr  7 13:16:33 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NE_LARGEFILE): Check for strtoq.\n\nMon Mar 15 19:59:36 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (LIBNEON_SOURCE_CHECKS): Be safer around getaddrinfo\n\tblacklist for HP-UX and reference why it's needed.\n\nSun Mar  7 11:15:44 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (LIBNEON_SOURCE_CHECKS): Use NE_LARGEFILE in-place\n\trather than AC_REQUIRE'ing it.\n\t(NE_LARGEFILE): Add NE_LFS to CPPFLAGS for use in bundled builds.\n\nMon Feb 23 23:02:54 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NE_SNPRINTF): Define HAVE_TRIO if trio is used.\n\nMon Feb 23 00:22:39 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (LIBNEON_SOURCE_CHECKS): Give INCLUDES argument to\n\tAC_CHECK_HEADERS; prevent warning from cpp test for netinet/in.h\n\ton some platforms.\n\nSun Feb 22 17:52:42 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NE_SEARCH_LIBS): Fix to run actions-if-found if\n\tfunction is found without needing additional libraries.\n\t(LIBNEON_SOURCE_CHECKS): Only check for gethostbyname if\n\tgetaddrinfo is not found.  Disable getaddrinfo on HP-UX 11.[01]*\n\there rather than ne_socket.c.\n\nSat Jan 24 17:49:50 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (LIBNEON_SOURCE_CHECKS): Also check for __tm_gmtoff in\n\tstruct tm.\n\nSat Jan 24 17:16:48 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4: Remove -ansi-pedantic and -Wimplicit-prototypes for gcc\n\t3.4 compatibility (thanks to Olaf Hering).\n \nSat Jan  3 14:11:14 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon-test.m4: Check for stdint.h.\n\nSat Jan  3 13:17:21 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NE_LARGEFILE): Add NE_LFS to neon-config --cflags\n\toutput.\n\nThu Jan  1 18:42:56 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NEON_FORMAT): Use C99 'll' rather than non-standard 'q'\n\tlength modifier.\n\nThu Jan  1 17:36:39 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NE_LARGEFILE): New macro.\n\t(LIBNEON_SOURCE_CHECKS): Call it.\n\nSat Nov 15 09:25:43 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4, neon-xml-parser.m4: Update for latest autoconf\n\tbest-practice: s/AC_HELP_STRING/AS_HELP_STRING, replace AC_TRY_RUN\n\twith AC_RUN_IFELSE, AC_TRY_LINK_FUNC with AC_LINK_IFELSE,\n\tAC_TRY_COMPILE with AC_COMPILE_IFELSE, remove AC_LANG_C and\n\tAC_PROG_CC_STDC,\n\nFri Nov 14 13:12:10 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NEON_LIBIDN): New macro.\n\t(LIBNEON_SOURCE_CHECKS): Use NEON_LIBIDN.\n\nFri Nov 14 11:28:58 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NE_ENABLE_SUPPORT, NE_DISABLE_SUPPORT): New macros.\n\tUse throughout to flag support or lack of support for optional\n\tfeatures.\n\nThu Nov 13 20:25:28 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (LIBNEON_SOURCE_CHECKS): Check for gethostbyname in\n\t-lbind too.\n\nTue Oct  7 21:20:16 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon-test.m4 (NEON_TEST): Check for shutdown.\n\nMon Sep 22 21:20:37 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NE_CHECK_FUNCS, NE_SEARCH_LIBS): Avoid clobbering\n\tne_save_{LIBS,CPPFLAGS}.\n\nSun Sep 14 10:51:34 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (LIBNEON_SOURCE_CHECKS): Check for working AI_ADDRCONFIG\n\tflag for getaddrinfo().\n\nWed Sep 10 21:45:10 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NEON_GSSAPI): Restore CPPFLAGS and NEON_LIBS if GSSAPI\n\tdetection fails.\n\nThu Sep  4 21:29:06 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (LIBNEON_SOURCE_CHECKS): Check for netinet/tcp.h.\n\nWed Jul 23 21:17:40 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NEON_GSSAPI): New macro.\n\nMon Apr 21 18:24:12 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon-xml-parser.m4 (HAVE_EXPAT): Fail if --with-expat is given\n\tbut expat.h is not found.\n\nWed Mar 26 20:29:11 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NEON_SSL): And add ne_stubssl to NEON_EXTRAOBJS for\n\tnon-SSL build.\n\nTue Mar 25 20:43:01 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NEON_SSL): Add ne_openssl to NEON_EXTRAOBJS.\n\nMon Mar 17 20:34:55 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (LIBNEON_SOURCE_CHECKS): Check for netdb.h.\n\nSun Mar 16 14:22:02 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon-xml-parser.m4 (NE_XML_BUNDLED_EXPAT): Define\n\tHAVE_XMLPARSE_H.\n\nSun Mar 16 11:47:35 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon-xml-parser.m4 (NEON_XML_PARSER): Also fix\n\tnon-included-expat build for when included expat is not an option.\n\nSun Mar 16 11:20:23 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon-xml-parser.m4 (NEON_XML_PARSER): Fix non-included-expat\n\tbuild broken in previous commit.\n\nSun Mar 16 09:06:41 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon-xml-parser.m4 (NEON_XML_PARSER): Fix --with-included-expat\n\tsupport.\n\nSun Mar  9 10:08:57 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NEON_SSL): Fail if --with-ssl is given an argument.\n\nSun Mar  9 08:55:04 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NE_SEARCH_LIBS): Bug fix to always compare against\n\t`extras' if given.  Add support for optional `actions-if-found'\n\targument.\n\n\t* neon-xml-parser.m4: Largely rewritten. Drop support for\n\tlibxml 1.x; require expat 1.95.x.\n\nSun Mar  9 08:50:22 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (LIBNEON_SOURCE_CHECKS): Check for stpcpy.\n\nMon Mar  3 22:15:56 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NE_CHECK_FUNCS): Check whether h_errno is declared.\n\nWed Feb 19 21:35:20 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NEON_FORMAT): Revert use of 'z' modifier; breaks on\n\tCygWin.\n\nTue Jan 14 17:06:07 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NEON_FORMAT): Prefer the C99 'z' modifier to printf\n\tsize_t/ssize_t values where available.\n\nFri Jan  3 23:12:20 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NE_PKG_CONFIG): New macro.\n\t(NEON_SSL): Use NE_PKG_CONFIG rather than PKG_CHECK_MODULES.\n\nMon Dec 16 20:02:45 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NEON_SSL): Only check for OpenSSL <=0.9.6 if version is\n\tknown to be <=0.9.7.\n\nMon Dec 16 19:01:57 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4: Use pkg-config data to determine location OpenSSL\n\tlibraries/headers, if available.\n\nTue Nov 19 11:21:31 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon-test.m4 (NEON_TEST): Suggest this macro is run before\n\tNEON_XML_PARSER.\n\nMon Oct  7 22:22:12 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NE_CHECK_SSLVER): New macro.\n\t(NEON_SSL): Use NE_CHECK_SSLVER.  Add --with-egd argument;\n\tconditionally enable EGD, optionally using only a specific EGD\n\tsocket path, and only if using OpenSSL before 0.9.7.\n\nTue Sep 24 21:36:01 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NE_ZLIB_VERSION): Removed macro.\n\t(NEON_ZLIB): Removed --with-force-zlib flag; don't check zlib\n\tversion.\n\t(NEON_SSL): Removed --with-force-ssl flag, only require OpenSSL\n\t0.9.6 or later.\n\nSat Aug 31 17:28:15 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NEON_FORMAT_PREP): Add check for gcc -Wformat -Werror\n\tsanity.\n\t(NEON_FORMAT): Only use gcc -Wformat -Werror if sanity is assured.\n\nFri Aug 30 22:07:59 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4: Set NEON_INTERFACE_VERSION according to\n\tNEON_VERSION_MINOR, NEON_VERSION_RELEASE, for the duration of neon\n\t0.x releases.\n\nSun Aug 25 23:52:38 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NE_CHECK_FUNCS): New macro.\n\t(LIBNEON_SOURCE_CHECKS): Use NE_CHECK_FUNCS rather than\n\tAC_CHECK_FUNCS, so $NEON_LIBS are searched.\n\nSun Aug 25 11:53:20 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (LIBNEON_SOURCE_CHECKS): Require inet_ntop as well for\n\tUSE_GETADDRINFO test.\t\n\nSun Aug 18 22:50:09 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (LIBNEON_SOURCE_CHECKS): Remove redundant check for\n\tSIGPIPE definition.\n\nSun Aug 18 22:41:15 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NE_SEARCH_LIBS): Take optional fourth argument.\n\t(LIBNEON_SOURCE_CHECKS): Define USE_GETADDRINFO if getaddrinfo and\n\tgai_strerror are present.  Otherwise, check for hstrerror,\n\tpossibly in -lresolv.\n\n\t* neon-test.m4: Don't check for hstrerror().\n\nSun Aug 18 22:31:13 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon-xml-parser.m4 (NEON_FIND_PARSER_H, NEON_XML_LIBXML2):\n\tRe-order checks to skip redundant tests, speeding up common case.\n\nFri Aug  9 19:47:14 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NEON_SSL): Require OpenSSL 0.9.6f or later.\n\nWed Jul 31 23:01:17 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* strftime.m4, readline.m4: Removed from neon/macros CVS module.\n\nTue Jul 30 19:09:20 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NEON_COMMON_CHECKS): Require AC_TYPE_SIZE_T,\n\tAC_TYPE_OFF_T.\n\n\t* neon-test.m4 (NEON_TEST): Require AC_TYPE_PID_T.\n\nTue Jul 30 19:06:48 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NEON_SSL): Require OpenSSL 0.9.6e or later for security\n\tfixes; add --with-force-ssl to override version check.\n\nFri Jul 26 00:01:07 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NE_MACOSX): Just check for any Darwin system.\n\nSat Jul 20 10:40:29 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NEON_WITH_LIBS): Allow a colon-separated list of\n\tdirectories for --with-libs argument.\n\nThu Jul 18 20:07:43 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (LIBNEON_SOURCE_CHECKS): Require AC_FUNC_STRERROR_R.\n\nWed Jul 17 23:26:51 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NEON_CHECK_VERSION): Rewrite to cache results,\n\tsimplify, and use new ne_version_match.\n\t(NE_ZLIB_VERSION): Cache result.\n\t\nFri Jul  5 12:57:56 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NEON_SSL): Fail if openssl/opensslv.h header is not\n\tfound, or if OpenSSL version is earlier than 0.9.6.\n\nSun Jun 16 14:04:18 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NEON_FORMAT): Take optional third argument giving \n\tformat string specifier to use.\n\t(NEON_COMMON_CHECKS): Get format string for ssize_t; fix to\n\tuse 'u' specifier for size_t format string.\n\nThu Jun 13 20:34:35 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon-xml-parser.m4 (NEON_XML_PARSER): Undocument use of =DIR\n\tparameter to --with-expat, as it gives false expectations.\n\nWed Jun 12 23:26:40 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NEON_WITH_LIBS): New macro.\n\nMon Jun 10 22:31:50 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NEON_WARNINGS): Replace -ansi-pedantic with -pedantic.\n\nSun May 26 19:08:12 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon-xml-parser.m4 (NEON_XML_LIBXML2): Check for\n\tlibxml/xmlversion.h header too.\n\nWed May 22 09:54:42 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NE_MACOSX): Cache result.\n\t(NE_COMMON_CHECKS): Simplify tm_gmtoff check further: use\n\tAC_CHECK_MEMBERS.\n\nMon May 20 21:18:06 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NE_SEARCH_LIBS): Cache results.\n\nMon May 20 20:55:04 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (LIBNEON_SOURCE_CHECKS): Use AC_CACHE_CHECK to check for\n\tSIGPIPE in signal.h; don't invade the ac_ namespace with cache\n\tvariables.  Cache results of tm_gmtoff test too.\n\nMon May 20 20:35:22 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NE_SNPRINTF): Simplify logic.\n\nSun May 19 20:23:55 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NEON_WARNINGS): Remove with_warnings variable;\n\tsimplify.\n\nWed May 19 08:36:44 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (LIBNEON_SOURCE_CHECKS): Declare stpcpy on modern\n\t\"Linux-like\" AIXes.\n\nSun May 19 09:35:08 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NE_FIND_AR): Fix $PATH handling on some Linux\n\tplatforms.\n\nSun May 19 09:05:22 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NE_FIND_AR): New macro.\n\t(NEON_NORMAL_BUILD): Require NE_FIND_AR.\n\n\t* neon-test.m4: Require NE_FIND_AR. Check for hstrerror().\n\nFri May 17 23:37:19 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NEON_SSL): Allow --without-ssl again.\n\nWed May 15 21:00:15 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon-xml-parser.m4 (NEON_XML_LIBXML2): sed '-L/usr/lib ' out of\n\txml2-config --libs output.\n\nSat May 11 15:30:38 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NEON_SOCKS): Moved and simplified from neon-socks.m4.\n\tDrop support for specifying directory argument; fail if\n\t--with-socks is given and socks.h is not found.\n\n\t* neon-socks.m4: Removed file.\n\nSat May 11 15:22:36 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NEON_DEBUG): Moved and simplified from neon-debug.m4.\n\n\t* neon-debug.m4: Removed file.\n\nSat May 11 13:40:29 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NEON_WARNINGS): Moved and simplified from\n\tneon-warnings.m4.\n\n\t* neon-warnings.m4: Removed file.\n\nSat May 11 13:26:00 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NEON_SSL): Simplified version of NEON_SSL from\n\tneon-ssl.m4.  Check for ssl.h; detect OpenSSL ENGINE correctly\n\twhen -lcrypto requries -ldl.\n\n\t* neon-ssl.m4: Removed file.\n\nSat May 11 13:16:27 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NE_SEARCH_LIBS): Allow passing 'extralibs' to include\n\tin library list when link against a specified library fails.\n\tPrepend found library/libraries to $NEON_LIBS.\n\nSat May 11 12:40:24 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon-xml-parser.m4 (NEON_XML_PARSER),\n\t* neon.m4 (NEON_REPLACE_SNPRINTF): \n\tUse AC_LIBOBJ rather than modify LIBOBJS directly, to appease\n\tautoconf 2.53.\n\nWed May  1 22:32:10 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon-xml-parser.m4 (NEON_XML_LIBXML1): Fix syntax error in\n\tlibxml 1.x detection causing spurious or missing warning message.\n\nThu Apr 25 07:38:33 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon-xml-parser.m4 (NEON_XML_EXTERNAL_EXPAT): Check for expat.h\n\ttoo, to support expat 1.95.x (Branko ibej).\n\nTue Apr 23 21:09:55 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon-xml-parser.m4 (NEON_FIND_PARSER_H): New macro, factored out\n\tfrom NEON_XML_LIBXML2.\n\t(NEON_XML_LIBXML2, NEON_XML_LIBXML1): Use it.\n\nTue Apr 23 20:54:30 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon-xml-parser.m4 (NEON_XML_LIBXML2): Check for parser.h or\n\tlibxml/parser.h, or fail.\n\nSat Apr 13 22:35:01 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NE_SNPRINTF): Define NEON_TRIO in NEON_CFLAGS, export\n\tit from 'neon-config --cflags' output.\n\nFri Apr  5 23:40:00 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NEON_ZLIB, NE_ZLIB_VERSION): Add --with-force-zlib, to\n\tskip zlib version check.  Simplify neon_zlib_message handling a\n\tlittle.\n\nTue Mar 12 00:18:00 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NE_ZLIB_VERSION): New macro.\n\t(NEON_ZLIB): Use it to require zlib 1.1.4.\n\nSun Mar 10 22:05:26 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NEON_ZLIB): Don't add ne_compress to NEON_EXTRAOBJS.\n\nMon Mar  4 21:04:28 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon-ssl.m4 (NEON_SSL): Avoid adding -I/usr/include to CFLAGS\n\tduring build as well as not exporting it via neon-config.\n\nTue Feb 19 21:30:50 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon-socks.m4 (NEON_SOCKS): Fix configure argument name, export\n\t-L argument in NEON_LIBS, check for socks.h not sock.h, define\n\tNEON_SOCKS.\n\nSun Jan 13 20:07:51 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NE_MACOSX): New macro.\n\t(NEON_COMMON_CHECKS): Call it.\n\nSun Jan  6 21:35:08 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon-xml-parser.m4 (NEON_XML_PARSER): Add XML_BYTE_ORDER to\n\tCPPFLAGS; mini-expat doesn't pick up config.h.\n\nTue Jan  1 23:30:03 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon-xml-parser.m4 (NEON_XML_PARSER): Set XML_BYTE_ORDER\n\tappropriately.\n\nTue Jan  1 22:50:15 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NEON_CHECK_VERSION): Don't add libs for external neon\n\tto NEON_LIBS here.\n\nTue Jan  1 22:44:05 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon-xml-parser.m4 (NEON_XML_LIBXML2, NEON_XML_LIBXML1): Alter\n\tCPPFLAGS only, not CFLAGS.\n\nTue Jan  1 21:49:16 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NEON_USE_EXTERNAL): Factored out from NEON_COMMON.\n\t(NEON_COMMON): Use NEON_USE_EXTERNAL; simplify, improve reporting.\n\t\n\t* neon.m4 (NEON_COMMON_CHECKS): Move check for common headers\n\there...  (LIBNEON_SOURCE_CHECKS): from here.\n\nTue Jan  1 21:44:33 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon-test.m4 (NEON_TEST): Check for AR and RANLIB.\n\nFri Dec 14 22:39:57 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon-test.m4 (NEON_TEST): Pick up time_t definition from\n\tsys/time.h if present (fix for Solaris 2.6 and probably\n\telsewhere).\n\nFri Dec 14 22:39:32 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NEON_FORMAT): Allow passing in headers where type may\n\tbe defined.\n\nMon Dec 10 07:36:26 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NEON_COMMON): Fix --with-neon=PATH again.\n\nSun Dec  9 21:40:47 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon-test.m4 (NEON_TEST): Determine how to print time_t.\n\nSun Dec  9 11:50:03 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NEON_WITHOUT_ACL): New macro.\n\t(LIBNEON_SOURCE_CHECKS): Conditionally build ACL support.\n\nSun Dec  9 01:06:32 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NEON_CHECK_VERSION): Use NEON_CONFIG as config script,\n\tdrop first argument.  Better error message if the link failed.\n\t(NEON_COMMON): Cleanup.  Check for neon-config in PATH.  Stop if\n\t--with-neon was given, and the external neon wasn't good enough.\n\nSun Dec  9 00:17:19 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon-test.m4 (NEON_TEST): Requires NEON_COMMON_CHECKS.\n\n\t* neon-warnings.m4 (NEON_WARNINGS): Requires AC_PROG_CC.\n\nSun Dec  9 00:13:47 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NEON_COMMON_CHECKS): New macro; runs common C\n\tlanguage/compiler checks, which may be useful to neon applications\n\tregardless of whether a bundled or external neon is being used.\n\tUse AC_REQUIRE to prevent macros being expanded more than once.\n\t(LIBNEON_SOURCE_CHECKS, NEON_COMMON): Require NEON_COMMON_CHECKS\n\tto have been expanded.\n\t\nSat Dec  8 00:56:34 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NEON_FORMAT): Rewrite to use cache results (should fix\n\tfor cross-compiling), and for GCC, actually test for warnings -\n\tfix for Linux.\n\nSat Dec  8 00:15:44 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NEON_CHECK_SUPPORT): Send --support output to\n\t/dev/null, in case it is from pre-0.18 and prints the usage\n\tmessage.\n\nSat Dec  8 00:13:55 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NEON_COMMON): Prepend -lneon to NEON_LIBS rather than\n\toverwriting it when using bundled build.\n\nMon Dec  3 19:49:28 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NEON_FORMAT_PREP, NEON_FORMAT): New macros.\n\t(LIBNEON_SOURCE_CHECKS): Call them.\n\nMon Dec  3 19:43:11 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\tFix gethostbyname() detection on Unixware 7:\n\n\t* neon.m4 (NEON_COMMON): Add -lneon to NEON_LIBS after performing\n\tsource checks.  (NE_SEARCH_LIBS): Test using libraries from\n\tNEON_LIBS too.\n\nSat Nov 24 20:33:11 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NEON_CHECK_SUPPORT): New macro.  (NEON_COMMON): Define\n\tNEON_SUPPORTS_{SSL,ZLIB} when using an external neon.\n\nSat Nov 24 20:25:15 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NEON_WITHOUT_ZLIB): New function.\n\t(LIBNEON_SOURCE_CHECKS): Conditionally enable zlib support.\n\nSun Nov 18 12:29:08 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon-ssl.m4 (NEON_SSL): Don't add -I/usr/include to NEON_CFLAGS.\n\nSat Oct 27 12:20:08 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4, neon-ssl.m4: Substitute NEON_SUPPORTS_ZLIB,\n\tNEON_SUPPORTS_DAV, NEON_SUPPORTS_SSL as \"yes\" or \"no\"\n\tappropriately.\n\nThu Oct 25 14:29:53 2001  Mo DeJong  <supermo@bayarea.net>\n\n        * neon.m4 (NEON_NORMAL_BUILD): Use AC_CHECK_TOOL instead of\n        AC_PATH_PROG so that cross compilation works properly.\n\nSat Oct  6 13:36:58 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NEON_ZLIB): New macro.  (LIBNEON_SOURCE_CHECKS):\n\tprint warning if struct tm lacks tm_gmtoff.\n\nSat Oct  6 12:39:09 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4: Require autoconf 2.50.  Use AC_HELP_STRING where\n\tpossible, and AC_MSG_NOTICE instead of 'echo'.\n\n\t* neon-ssl.m4, neon-xml-parser.m4, neon-socks.m4: Quoting fixes\n\tfor help strings.\n\nTue Oct  2 21:13:24 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (LIBNEON_SOURCE_CHECKS): Check for tm_gmtoff in struct\n\ttm.\n\nSun Sep 30 23:35:03 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NE_SEARCH_LIBS): AC_SEARCH_LIBS replacement, adds found\n\tlibraries to NEON_LIBS instead.\n\nSun Sep 30 11:11:19 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon-test.m4: New file.\n\nSun Sep 30 11:09:58 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4, neon-xml-parser.m4: Always add libs to $LIBS rather\n\tthan $NEONLIBS.\n\n\t* neon.m4: Export NEON_CFLAGS.\n\nSat Sep 29 14:12:53 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (LIBNEON_SOURCE_CHECKS): Check for zlib (zlib.h, inflate\n\tin -lz).  Add ne_compress to NEON_EXTRAOBJS.\n\nTue Sep 25 07:31:53 2001  Mo DeJong  <supermo@bayarea.net>\n\n        * neon.m4 (LIBNEON_SOURCE_CHECKS): Check for <signal.h> instead of\n\t<sys/signal.h>. Define HAVE_SIGPIPE if SIGPIPE is defined in\n\t<signal.h>.\n\nMon Sep 24 20:16:47 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon-xml-parser.m4 (NEON_XML_EXTERNAL_EXPAT): Fix broken\n\tAC_DEFINE (Mo DeJong).\n\nMon Sep 24 17:24:42 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ac_c_bigendian_cross.m4: New file.\n\n\t* neon.m4: Use AC_C_BIGENDIAN_CROSS rather than AC_C_BIGENDIAN.\n\nMon Sep 17 23:29:11 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (LIBNEON_SOURCE_CHECKS): Check for setvbuf().\n\nSun Sep 16 20:39:05 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon-ssl.m4 (NEON_SSL): Put SSL libs in LIBS rather than\n\tNEONLIBS (and lib paths).\n\nSun Sep 16 20:36:53 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NEON_COMMON): Add library paths to NEONLIBS rather than\n\tLDFLAGS.\n\nSat Jun  9 22:06:25 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon-debug.m4: New file.\n\nThu May 31 00:04:51 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NEON_COMMON_BUILD): Update filenames.\n\t(NEON_CHECK_VERSION): Do simple AC_TRY_LINK and warn appropriately\n\tbefore checking version.\n\nThu May 31 00:03:40 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon-warnings.m4: Add -Wbad-function-cast.\n\nWed May 30 23:37:48 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon-xml-parser.m4: Added --with-libxml1 and --with-libxml2\n\targuments.\n\nTue Apr 17 23:06:25 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon-ssl.m4: Define neon_ssl_message for configure output.\n\nWed Apr 11 23:14:33 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NEON_COMMON_BUILD): Fix specifying a list of object\n\tfiles.\n\nFri Apr  6 23:09:58 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (LIBNEON_SOURCE_CHECKS): Call NEON_SOCKS.\n\nFri Apr  6 23:08:39 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon-socks.m4: Add basic SOCKSv5 support (untested).\n\nMon Apr  2 21:42:40 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4: Version is 0.13.0, interface version 13:0:0.\n\nMon Apr  2 00:27:37 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4: Move check for 'ar' program to NEON_NORMAL_BUILD, it's\n\tnot necessary for libtool build.\n\nMon Apr  2 00:17:58 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon-xml-parser.m4 (NEON_XML_PARSER): Check for xmlversion.h\n\theader from libxml2.\n\nSun Apr  1 21:23:26 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon-xml-parser.m4: Add expat2 support (Sam TH <sam@uchicago.edu>).\n\nWed Mar 21 10:56:03 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon-xml-parser.m4: Add libxml2 support.\n\nSun Mar  4 15:45:21 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon-xml-parser.m4 (NEON_XML_PARSER): Use an m4 ifelse rather\n\tthan a shell test to code the conditional on whether an argument\n\twas passed to the macro or not.\n\nSun Mar  4 15:23:47 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4: Add \"actions if not bundled\" argument to *_BUNDLED\n\tmacros.\n\nMon Feb 26 22:52:24 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4: Version is 0.12.0.\n\nMon Feb 26 22:06:13 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4: Versionn is 0.12.0-dev.\n\nSun Feb 25 17:12:49 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (LIBNEON_SOURCE_CHECKS): Add checks for endianness (for\n\tmd5 code), inline, and const.\n\nSun Feb 25 17:00:07 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NEON_COMMON): Rename NEON_IS_BUNDLED to\n\tNEON_BUILD_BUNDLED.\n\nSun Feb 25 16:52:19 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NEON_COMMON): Define NEON_IS_BUNDLED to \"yes\" or \"no\"\n\tappropriately.\n\nSat Feb 24 00:06:09 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (LIBNEON_SOURCE_CHECKS): Don't set NEON_NEED_XML_PARSER\n\there.  (NEON_COMMON): ... set it here instead.\n\t(NEON_WITHOUT_WEBDAV): New macro to disable WebDAV support.\n\t(NEON_COMMON_BUILD): Select default set of object files to build\n\tdepending on whether DAV is enabled or not.\n\nFri Feb 23 23:28:09 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NEON_COMMON_BUILD): Use an m4 'ifelse' for the number\n\tof args test.\n\n\t* neon.m4 (NEON_LIBTOOL_BUILD, NEON_NORMAL_BUILD,\n\tNEON_COMMON_BUILD): Set NEON_OBJEXT correctly (fixes\n\tdependancies).\n\nSun Feb  4 14:55:10 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4: Version is 0.11.0, interface version is 11:0:0.\n\nSun Jan 28 17:16:27 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NEON_CHECK_VERSION): Run actions-if-okay if\n\tNEON_REQUIRE has not been called.\n\nSun Jan 28 14:53:57 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4 (NEON_REQUIRE, NEON_CHECK_VERSION): New macros.\n\t(NEON_COMMON): If a required version is defined, check that an\n\texternal neon library matches it.\n\nSun Jan 28 10:39:31 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4: Define NEON_VERSION, NEON_VERSION_{MAJOR,MINOR} in\n\tconfig.h rather than substituting into neon_config.h.\n\nSat Jan 27 22:55:42 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon.m4: Include version string in library message.\n\nTue Jan 23 23:14:33 2001  Joe Orton  <joe@light.plus.com>\n\n\t* neon.m4 (NEON_VERSIONS): New macro.  (NEON_COMMON): Call it from\n\there.\n\nMon Jan 15 22:26:54 2001  Joe Orton  <joe@light.plus.com>\n\n\t* neon-xml-parser.m4 (NEON_XML_PARSER): Append rather than\n\toverwrite CFLAGS.\n\nThu Jan 11 20:49:12 2001  Joe Orton  <joe@light.plus.com>\n\n\t* neon-ssl.m4: Check for OpenSSL in /usr too.\n\nThu Jan 11 20:05:34 2001  Joe Orton  <joe@light.plus.com>\n\n\t* neon.m4 (NEON_VPATH_BUNDLED): New macro.  (NEON_BUNDLED): Call\n\tNEON_COMMON_BUNDLED.  (NEON_COMMON_BUNDLED): Abstracted from\n\tNEON_BUNDLED.\n\nWed Jan 10 22:44:37 2001  Joe Orton  <joe@light.plus.com>\n\n\t* neon.m4 (NEON_LIBTOOL_BUILD, NEON_NORMAL_BUILD): Pass optional\n\tset of objects to build to these macros.  Else, all objects go in\n\tNEONOBJS.  (NEON_COMMON_BUILD): Implement that.  Also substitute\n\tNEON_LINK_FLAGS. \n\nMon Jan  8 22:23:51 2001  Joe Orton  <joe@light.plus.com>\n\n\t* neon-xml-parser.m4 (NEON_XML_PARSER): Put XML parser libs in\n\t$NEONLIBS rather than $LIBS.\n\nMon Jan  8 22:20:51 2001  Joe Orton  <joe@light.plus.com>\n\n\t* neon-ssl.m4 (NEON_SSL): Put OpenSSL libs in $NEONLIBS rather\n\tthan LIBS.\n\nSun Jan  7 17:30:54 2001  Joe Orton  <joe@light.plus.com>\n\n\t* neon.m4 (NEON_BUNDLED): Add optional second argument to specify\n\tbuilddir of bundled sources (Peter Moulder <pjm@bofh.asn.au>).\n\nWed Jan  3 21:33:05 2001  Joe Orton  <joe@light.plus.com>\n\n\t* neon.m4: Place libraries needed to use neon in NEONLIBS.  Adding\n\tthem to LIBS breaks bundled builds since libneon doesn't exist at\n\tconfigure-time, and configure uses $LIBS.\n\nWed Jan  3 21:17:00 2001  Joe Orton  <joe@light.plus.com>\n\n\t* neon.m4 (NEON_COMMON_BUILD): Don't set top_builddir using 'pwd'.\n\nWed Jan  3 21:15:04 2001  Joe Orton  <joe@light.plus.com>\n\n\t* neon.m4 (NEON_COMMON): If using bundled neon, add -L<bundled\n\tdir> to LDFLAGS, and -lneon to LIBS.\n\nFri Dec 22 23:13:39 2000  Joe Orton  <joe@light.plus.com>\n\n\t* neon.m4 (NEON_NORMAL_BUILD, NEON_COMMON_BUILD): New macros.\n\nTue Dec 19 22:13:18 2000  Joe Orton  <joe@light.plus.com>\n\n\t* neon.m4 (NEON_LIBTOOL_BUILD): New macro.\n\nWed Dec 13 22:07:07 2000  Joe Orton  <joe@light.plus.com>\n\n\t* neon.m4: Add a decent interface: NEON_LIBRARY for non-bundled\n\tcase, NEON_BUNDLED for the bundled case.  (LIBNEON_SOURCE_CHECKS):\n\tAlways set NEON_NEED_XML_PARSER.\n\n\t* neon-xml-parser.m4 (NEON_XML_PARSER): Only execute if\n\t\"$NEON_NEED_XML_PARSER\" = \"yes\".\n\nSun Nov 19 22:52:56 2000  Joe Orton  <joe@light.plus.com>\n\n\t* neon.m4, neon-ssl.m4, neon-warnings.m4, neon-xml-parser.m4:\n\tClarify that the more liberal license applies to the m4 files\n\tonly, not neon in general.\n\nSun Nov 19 22:40:01 2000  Joe Orton  <joe@light.plus.com>\n\n\t* neon.m4 (NEON_LIBRARY): Don't call NEON_XML_PARSER, set\n\tNEON_NEED_XML_PARSER to \"yes\" if it needs to be called.\n\nSun Nov 19 22:31:26 2000  Joe Orton  <joe@light.plus.com>\n\n\t* neon-xml-parser.m4 (NEON_XML_PARSER): Switch to useing\n\tNEON_INCLUDED_EXPAT m4 macro rather than passing arguments.\n\nSun Nov 19 22:20:36 2000  Joe Orton  <joe@light.plus.com>\n\n\t* neon.m4 (NEON_LIBRARY): Switch to using NEON_INCLUDED_SOURCE m4\n\tmacro rather than passing arguments to the NEON_LIBRARY macro.\n\t\nSun Nov  5 23:26:18 2000  Joe Orton  <joe@light.plus.com>\n\n\t* neon-xml-parser.m4: Never set LIBS if using a libtool-built\n\tlibexpat.la (Greg Stein).\n\n2000-10-10  Joe Orton  <joe@monolith.orton.local>\n\n\t* neon-xml-parser.m4: If libexpat.la is included in the\n\t--with-expat parameter, then use a libtool-friendly LIBS. (Greg\n\tStein)\n\nSat Oct  7 19:16:08 2000  Joe Orton  <joe@light.plus.com>\n\n\t* neon-xml-parser.m4: Link against a libexpat.la if found in\n\t--with-expat location. (Greg Stein).\n\nMon Sep 11 15:05:58 2000  Joe Orton  <joe@light.plus.com>\n\n\t* neon.m4: Use AC_SEARCH_LIBS for finding gethostbyname() and\n\tsocket().\n\nMon Sep 11 15:03:45 2000  Joe Orton  <joe@light.plus.com>\n\n\t* neon.m4 (NEON_REPLACE_SNPRINTF): New macro.\n\nFri Sep  8 14:30:37 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* neon.m4: Check for socket() in -lsocket, -linet.\n\nThu Sep  7 00:11:51 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* neon-xml-parser.m4: Added --with-expat flag (patch by Greg\n\tStein).\n\nSun Aug 13 11:12:41 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* strftime.m4: New file, from fileutils-4.0i.\n\nThu Jul 27 19:59:18 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* neon-ssl.m4: Append the SSL libs on the end of $LIBS rather than\n\tredefining it completely.\n\nThu Jul 27 19:43:38 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* neon.m4: Define variable neon_library_message to describe what\n\tneon library is being used.\n\nMon Jul 24 16:56:34 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* neon-ssl.m4: Put -lssl before -lcrypto in LIBS.\n\nThu Jul 20 15:12:14 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* neon-xml-parser.m4 (NEON_XML_PARSER): Pass directory name\n\tcontaining bundled expat sources as $1.\n\n\t* neon.m4 (NEON_LIBRARY): Pass directory name containing bundled\n\tneon sources as $1, and $2 is passed to NEON_XML_PARSER for\n\tsimilar use.\n\nThu Jul 20 15:04:49 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* neon-ssl.m4: Rewritten from scratch. Support OpenSSL only.\n\nThu Jul 20 12:41:23 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* neon.m4, neon-xml-parser.m4, neon_warnings.m4: Added licensing\n\tinformation.\n\nWed Jul 19 19:30:24 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* neon-warnings.m4: New file. (NEON_WARNINGS): Macro for doing\n\t--enable-warnings.\n\nSun Jun 18 12:12:23 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* neon.m4: Only add --with-included-neon flag if neon is bundled.\n\nSun Jun 18 12:08:23 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* gnome-x-checks.m4: Imported from GNOME CVS macros module,\n\tadding: descriptive args to AC_DEFINE HAVE_LIBSM call, requiring\n\tGtk 1.2.8 and the Gtk 'gthread' module.\n\nMon May 29 15:10:24 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* neon.m4 (LIBNEON_SOURCE_CHECKS): Call NEON_SSL.\n\nTue May 23 19:11:29 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* neon.m4: Renamed from neon-checks.m4.\n\nSun May 21 23:52:27 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* neon-ssl.m4: New file.\n\nSat May 13 21:08:54 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* acconfig.h: Added HAVE_LC_MESSAGE (my lcmessage.m4 is missing\n\tthe appropriate description arguments).\n\nSat May 13 21:08:40 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* acconfig.h: Added PACKAGE and VERSION.\n\nSat May 13 21:02:29 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* socklen-arg-type.m4: Added file, modified from a KDE\n\tconfigure.in.\n\nSat May 13 20:44:56 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* gnome-x-checks.m4: Added description arguments to\n\tAC_DEFINE(HAVE_LIBSM).\n\nWed May 10 19:18:14 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* neon-xml-parser.m4: Error if no XML parser is found.\n\nWed May 10 14:33:21 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* neon-checks.m4: New file.\n\nWed May 10 14:26:57 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* neon-xml-parser.m4 (NEON_XML_PARSER): Use \"neon_\" prefix for\n\tvariables.\n\nWed May 10 13:47:04 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* acconfig.h: New file.\n\nWed May 10 13:42:16 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* neon-xml-parser.m4: New file.\n\nSun May  7 21:57:32 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* gnome-x-checks.m4 (GNOME_X_CHECKS): Check for Gtk 1.2.7 or\n\tlater, passing \"gthread\" module argument.\n\n"
  },
  {
    "path": "macros/ld-version-script.m4",
    "content": "# ld-version-script.m4 serial 3\ndnl Copyright (C) 2008-2013 Free Software Foundation, Inc.\ndnl This file is free software; the Free Software Foundation\ndnl gives unlimited permission to copy and/or distribute it,\ndnl with or without modifications, as long as this notice is preserved.\n\ndnl From Simon Josefsson\n\n# FIXME: The test below returns a false positive for mingw\n# cross-compiles, 'local:' statements does not reduce number of\n# exported symbols in a DLL.  Use --disable-ld-version-script to work\n# around the problem.\n\n# gl_LD_VERSION_SCRIPT\n# --------------------\n# Check if LD supports linker scripts, and define automake conditional\n# HAVE_LD_VERSION_SCRIPT if so.\nAC_DEFUN([gl_LD_VERSION_SCRIPT],\n[\n  AC_ARG_ENABLE([ld-version-script],\n    AS_HELP_STRING([--enable-ld-version-script],\n      [enable linker version script (default is enabled when possible)]),\n      [have_ld_version_script=$enableval], [])\n  if test -z \"$have_ld_version_script\"; then\n    AC_MSG_CHECKING([if LD -Wl,--version-script works])\n    save_LDFLAGS=\"$LDFLAGS\"\n    LDFLAGS=\"$LDFLAGS -Wl,--version-script=conftest.map\"\n    cat > conftest.map <<EOF\nfoo\nEOF\n    AC_LINK_IFELSE([AC_LANG_PROGRAM([], [])],\n                   [accepts_syntax_errors=yes], [accepts_syntax_errors=no])\n    if test \"$accepts_syntax_errors\" = no; then\n      cat > conftest.map <<EOF\nVERS_1 {\n        global: sym;\n};\n\nVERS_2 {\n        global: sym;\n} VERS_1;\nEOF\n      AC_LINK_IFELSE([AC_LANG_PROGRAM([], [])],\n                     [have_ld_version_script=yes], [have_ld_version_script=no])\n    else\n      have_ld_version_script=no\n    fi\n    rm -f conftest.map\n    LDFLAGS=\"$save_LDFLAGS\"\n    AC_MSG_RESULT($have_ld_version_script)\n  fi\n  AM_CONDITIONAL(HAVE_LD_VERSION_SCRIPT, test \"$have_ld_version_script\" = \"yes\")\n])\n"
  },
  {
    "path": "macros/neon-test.m4",
    "content": "# Copyright (C) 2001-2022 Joe Orton <joe@manyfish.co.uk>    -*- autoconf -*-\n#\n# This file is free software; you may copy and/or distribute it with\n# or without modifications, as long as this notice is preserved.\n# This software is distributed in the hope that it will be useful, but\n# WITHOUT ANY WARRANTY, to the extent permitted by law; without even\n# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR\n# PURPOSE.\n\n# The above license applies to THIS FILE ONLY, the neon library code\n# itself may be copied and distributed under the terms of the GNU\n# LGPL, see COPYING.LIB for more details\n\n# This file is part of the neon HTTP/WebDAV client library.\n# See https://notroj.github.io/neon/ for the latest version. \n# Please report feedback via <https://github.com/notroj/neon/>\n\n# Tests needed for the neon-test common test code.\n\nAC_DEFUN([NEON_TEST], [\n\nAC_REQUIRE([NEON_COMMON_CHECKS])\nAC_REQUIRE([NE_FORMAT_TIMET])\n\nAC_REQUIRE([AC_TYPE_PID_T])\n\ndnl NEON_XML_PARSER may add things (e.g. -I/usr/local/include) to \ndnl CPPFLAGS which make \"gcc -Werror\" fail in NEON_FORMAT; suggest\ndnl this macro is used first.\nAC_BEFORE([$0], [NEON_XML_PARSER])\n\nAC_CHECK_HEADERS(sys/time.h signal.h stdint.h locale.h sys/endian.h endian.h)\n\nAC_CHECK_FUNCS(pipe isatty usleep shutdown setlocale gethostname)\n\nAC_REQUIRE([NE_FIND_AR])\n\n])\n\nAC_DEFUN([NEON_TEST_WITHOUT_CHILD], [\nAC_DEFINE([NEON_NO_TEST_CHILD], 1, [Define if test suite child process handling is not needed])\n])\n"
  },
  {
    "path": "macros/neon-xml-parser.m4",
    "content": "# Copyright (C) 1998-2022 Joe Orton <joe@manyfish.co.uk>    -*- autoconf -*-\n#\n# This file is free software; you may copy and/or distribute it with\n# or without modifications, as long as this notice is preserved.\n# This software is distributed in the hope that it will be useful, but\n# WITHOUT ANY WARRANTY, to the extent permitted by law; without even\n# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR\n# PURPOSE.\n\n# The above license applies to THIS FILE ONLY, the neon library code\n# itself may be copied and distributed under the terms of the GNU\n# LGPL, see COPYING.LIB for more details\n\n# This file is part of the neon HTTP/WebDAV client library.\n# See https://notroj.github.io/neon/ for the latest version. \n# Please report feedback via <https://github.com/notroj/neon/>\n\n# Check for XML parser, supporting libxml 2.x and expat 1.95.x,\n# or a bundled copy of expat.\n#  *  Bundled expat if a directory name argument is passed\n#     -> expat dir must contain minimal expat sources, i.e.\n#        xmltok, xmlparse sub-directories.  See sitecopy/cadaver for\n#\t examples of how to do this.\n#\n# Usage: \n#  NEON_XML_PARSER()\n# or\n#  NEON_XML_PARSER([expat-srcdir], [expat-builddir])\n\ndnl Find expat: run $1 if found, else $2\nAC_DEFUN([NE_XML_EXPAT], [\nAC_CHECK_HEADER(expat.h,\n  [AC_CHECK_LIB(expat, XML_SetXmlDeclHandler, [\n    AC_DEFINE(HAVE_EXPAT, 1, [Define if you have expat])\n    neon_xml_parser_message=\"expat\"\n    NEON_LIBS=\"$NEON_LIBS -lexpat\"\n    neon_xml_parser=expat\n    AC_CHECK_TYPE(XML_Size, \n      [NEON_FORMAT(XML_Size, [#include <expat.h>])],\n      [AC_DEFINE_UNQUOTED([NE_FMT_XML_SIZE], [\"d\"])],\n      [#include <expat.h>])\n  ], [$1])], [$1])\n])\n\ndnl Find libxml2: run $1 if found, else $2\nAC_DEFUN([NE_XML_LIBXML2], [\nNE_PKG_CONFIG(NE_LX2, libxml-2.0,\n   [],\n   [AC_CHECK_TOOL(XML2_CONFIG, xml2-config)\n    if test \"x$XML2_CONFIG\" != \"xno\"; then\n      # xml2-config in some versions erroneously includes -I/include\n      # in the --cflags output.\n      NE_LX2_VERSION=\"`$XML2_CONFIG --version`\"\n      NE_LX2_CFLAGS=\"`$XML2_CONFIG --cflags | sed 's| -I/include||g'`\"\n      NE_LX2_LIBS=\"`$XML2_CONFIG --libs | sed 's|-L/usr/lib ||g'`\"\n    fi])\n\nif test -n \"${NE_LX2_VERSION+set}\"; then\n    neon_xml_parser_message=\"libxml $NE_LX2_VERSION\"\n    AC_DEFINE(HAVE_LIBXML, 1, [Define if you have libxml])\n    CPPFLAGS=\"$CPPFLAGS $NE_LX2_CFLAGS\"\n    NEON_LIBS=\"$NEON_LIBS $NE_LX2_LIBS\"\n    AC_CHECK_HEADERS(libxml/xmlversion.h libxml/parser.h,,[\n      AC_MSG_ERROR([could not find parser.h, libxml installation problem?])])\n    neon_xml_parser=libxml2\nelse\n    $1\nfi\n])\n\ndnl Configure for a bundled expat build.\nAC_DEFUN([NE_XML_BUNDLED_EXPAT], [\n\nAC_REQUIRE([AC_C_BIGENDIAN])\n# Define XML_BYTE_ORDER for expat sources.\nif test $ac_cv_c_bigendian = \"yes\"; then\n  ne_xml_border=21\nelse\n  ne_xml_border=12\nfi\n\n# mini-expat doesn't pick up config.h\nCPPFLAGS=\"$CPPFLAGS -DXML_BYTE_ORDER=$ne_xml_border -DXML_DTD -I$1/xmlparse -I$1/xmltok\"\n\nAC_DEFINE_UNQUOTED([NE_FMT_XML_SIZE], [\"d\"])\n\n# Use the bundled expat sources\nAC_LIBOBJ($2/xmltok/xmltok)\nAC_LIBOBJ($2/xmltok/xmlrole)\nAC_LIBOBJ($2/xmlparse/xmlparse)\nAC_LIBOBJ($2/xmlparse/hashtable)\n\nAC_DEFINE(HAVE_EXPAT)\n\nAC_DEFINE(HAVE_XMLPARSE_H, 1, [Define if using expat which includes xmlparse.h])\n\n])\n\nAC_DEFUN([NEON_XML_PARSER], [\n\ndnl Switches to force choice of library\nAC_ARG_WITH([libxml2],\nAS_HELP_STRING([--with-libxml2], [force use of libxml 2.x]))\nAC_ARG_WITH([expat], \nAS_HELP_STRING([--with-expat], [force use of expat]))\n\ndnl Flag to force choice of included expat, if available.\nifelse($#, 2, [\nAC_ARG_WITH([included-expat],\nAS_HELP_STRING([--with-included-expat], [use bundled expat sources]),,\nwith_included_expat=no)],\nwith_included_expat=no)\n\nif test \"$NEON_NEED_XML_PARSER\" = \"yes\"; then\n  # Find an XML parser\n  neon_xml_parser=none\n\n  # Forced choice of expat:\n  case $with_expat in\n  yes) NE_XML_EXPAT([AC_MSG_ERROR([expat library not found, cannot proceed])]) ;;\n  no) ;;\n  */libexpat.la) \n       # Special case for Subversion\n       ne_expdir=`echo $with_expat | sed 's:/libexpat.la$::'`\n       AC_DEFINE(HAVE_EXPAT)\n       AC_DEFINE_UNQUOTED([NE_FMT_XML_SIZE], [\"d\"])\n       CPPFLAGS=\"$CPPFLAGS -I$ne_expdir\"\n       if test \"x${NEON_TARGET}\" = \"xlibneon.la\"; then\n         NEON_LTLIBS=$with_expat\n       else\n         # no dependency on libexpat => crippled libneon, so do partial install\n         ALLOW_INSTALL=lib\n       fi\n       neon_xml_parser=expat\n       neon_xml_parser_message=\"expat in $ne_expdir\"\n       ;;\n  /*) AC_MSG_ERROR([--with-expat does not take a directory argument]) ;;\n  esac\n\n  # If expat wasn't specifically enabled and libxml was:\n  if test \"${neon_xml_parser}-${with_libxml2}-${with_included_expat}\" = \"none-yes-no\"; then\n     NE_XML_LIBXML2(\n      [AC_MSG_ERROR([libxml2.x library not found, cannot proceed])])\n  fi\n\n  # Otherwise, by default search for expat then libxml2:\n  if test \"${neon_xml_parser}-${with_included_expat}\" = \"none-no\"; then\n     NE_XML_EXPAT([NE_XML_LIBXML2([:])])\n  fi\n\n  # If an XML parser still has not been found, fail or use the bundled expat\n  if test \"$neon_xml_parser\" = \"none\"; then\n    m4_if($1, [], \n       [AC_MSG_ERROR([no XML parser was found: expat or libxml 2.x required])],\n       [# Configure the bundled copy of expat\n        NE_XML_BUNDLED_EXPAT($@)\n\tneon_xml_parser_message=\"bundled expat in $1\"])\n  fi\n\n  AC_MSG_NOTICE([XML parser used: $neon_xml_parser_message])\nfi\n\n])\n"
  },
  {
    "path": "macros/neon.m4",
    "content": "# Copyright (C) 1998-2009 Joe Orton <joe@manyfish.co.uk>    -*- autoconf -*-\n# Copyright (C) 2004 Aleix Conchillo Flaque <aleix@member.fsf.org>\n#\n# This file is free software; you may copy and/or distribute it with\n# or without modifications, as long as this notice is preserved.\n# This software is distributed in the hope that it will be useful, but\n# WITHOUT ANY WARRANTY, to the extent permitted by law; without even\n# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR\n# PURPOSE.\n\n# The above license applies to THIS FILE ONLY, the neon library code\n# itself may be copied and distributed under the terms of the GNU\n# LGPL, see COPYING.LIB for more details\n\n# This file is part of the neon HTTP/WebDAV client library.\n# See https://notroj.github.io/neon/ for the latest version. \n# Please report feedback via <https://github.com/notroj/neon/>\n\n#\n# Usage:\n#\n#      NEON_LIBRARY\n# or   NEON_BUNDLED(srcdir, [ACTIONS-IF-BUNDLED], [ACTIONS-IF-NOT_BUNDLED]) \n# or   NEON_VPATH_BUNDLED(srcdir, builddir, \n#\t\t\t  [ACTIONS-IF-BUNDLED], [ACTIONS-IF-NOT-BUNDLED])\n#\n#   where srcdir is the location of bundled neon 'src' directory.\n#   If using a VPATH-enabled build, builddir is the location of the\n#   build directory corresponding to srcdir.\n#\n#   If a bundled build *is* being used, ACTIONS-IF-BUNDLED will be\n#   evaluated. These actions should ensure that 'make' is run\n#   in srcdir, and that one of NEON_NORMAL_BUILD or NEON_LIBTOOL_BUILD \n#   is called.\n#\n# After calling one of the above macros, if the NEON_NEED_XML_PARSER\n# variable is set to \"yes\", then you must configure an XML parser\n# too. You can do this your own way, or do it easily using the\n# NEON_XML_PARSER() macro. Example usage for where we have bundled the\n# neon sources in a directory called libneon, and bundled expat\n# sources in a directory called 'expat'.\n#\n#   NEON_BUNDLED(libneon, [\n#\tNEON_XML_PARSER(expat)\n#\tNEON_NORMAL_BUILD\n#   ])\n#\n# Alternatively, for a simple standalone app with neon as a\n# dependancy, use just:\n#\n#   NEON_LIBRARY\n# \n# and rely on the user installing neon correctly.\n#\n# You are free to configure an XML parser any other way you like,\n# but the end result must be, either expat or libxml will get linked\n# in, and HAVE_EXPAT or HAVE_LIBXML is defined appropriately.\n#\n# To set up the bundled build environment, call \n#\n#    NEON_NORMAL_BUILD\n# or\n#    NEON_LIBTOOL_BUILD\n# \n# depending on whether you are using libtool to build, or not.\n# Both these macros take an optional argument specifying the set\n# of object files you wish to build: if the argument is not given,\n# all of neon will be built.\n\nAC_DEFUN([NEON_BUNDLED],[\n\nneon_bundled_srcdir=$1\nneon_bundled_builddir=$1\n\nNEON_COMMON_BUNDLED([$2], [$3])\n\n])\n\nAC_DEFUN([NEON_VPATH_BUNDLED],[\n\nneon_bundled_srcdir=$1\nneon_bundled_builddir=$2\nNEON_COMMON_BUNDLED([$3], [$4])\n\n])\n\nAC_DEFUN([NEON_COMMON_BUNDLED],[\n\nAC_PREREQ(2.50)\n\nAC_ARG_WITH(included-neon,\nAS_HELP_STRING([--with-included-neon], [force use of included neon library]),\n[neon_force_included=\"$withval\"], [neon_force_included=\"no\"])\n\nNEON_COMMON\n\n# The colons are here so there is something to evaluate\n# in case the argument was not passed.\nif test \"$neon_force_included\" = \"yes\"; then\n\t:\n\t$1\nelse\n\t:\n\t$2\nfi\n\nAC_CONFIG_FILES([${neon_bundled_builddir}/Makefile])\n\n])\n\ndnl Not got any bundled sources:\nAC_DEFUN([NEON_LIBRARY],[\n\nAC_PREREQ(2.50)\nneon_force_included=no\nneon_bundled_srcdir=\nneon_bundled_builddir=\n\nNEON_COMMON\n\n])\n\nAC_DEFUN([NE_DEFINE_VERSIONS], [\n\nNEON_VERSION=\"${NE_VERSION_MAJOR}.${NE_VERSION_MINOR}.${NE_VERSION_PATCH}${NE_VERSION_TAG}\"\n\nAC_DEFINE_UNQUOTED([NEON_VERSION], [\"${NEON_VERSION}\"],\n                   [Define to be the neon version string])\nAC_DEFINE_UNQUOTED([NE_VERSION_MAJOR], [(${NE_VERSION_MAJOR})],\n                   [Define to be neon library major version])\nAC_DEFINE_UNQUOTED([NE_VERSION_MINOR], [(${NE_VERSION_MINOR})],\n                   [Define to be neon library minor version])\nAC_DEFINE_UNQUOTED([NE_VERSION_PATCH], [(${NE_VERSION_PATCH})],\n                   [Define to be neon library patch version])\n])\n\nAC_DEFUN([NE_VERSIONS_BUNDLED], [\n\n# Define the current versions.\nNE_VERSION_MAJOR=0\nNE_VERSION_MINOR=37\nNE_VERSION_PATCH=1\nNE_VERSION_TAG=\n\n# 0.37.x is backwards-compatible to 0.27.x, so AGE=10\nNE_LIBTOOL_VERSINFO=\"37:${NE_VERSION_PATCH}:10\"\n\nNE_DEFINE_VERSIONS\n\n])\n\ndnl Adds an ABI variation tag which will be added to the SONAME of\ndnl a shared library.  e.g. NE_ADD_ABITAG(FOO)\nAC_DEFUN([NE_ADD_ABITAG], [\nif test \"x${NE_LIBTOOL_RELEASE}y\" = \"xy\"; then\n   NE_LIBTOOL_RELEASE=\"$1\"\nelse\n   NE_LIBTOOL_RELEASE=\"${NE_LIBTOOL_RELEASE}-$1\"\nfi\n])\n\ndnl Define the minimum required version, usage:\ndnl   NE_MINIMUM_VERSION([major-version], [minor-version])\ndnl If a major-version of 0 is used, neon 1.x will be allowed\ndnl as backward compatible. FOr example:\ndnl   NE_MINIMUM_VERSION([0], [27])\ndnl require neon 0.27.x or later or any 1.x\nAC_DEFUN([NE_MINIMUM_VERSION], [\nm4_define([ne_require_major], [$1])\n# ## ne_require_major $1\nm4_define([ne_require_minor], [$2])\n# ## ne_require_minor $2\n])\n\n\ndnl Deprecated.\nAC_DEFUN([NE_REQUIRE_VERSIONS], [\n# Extract the first minor version from the list:\nNE_MINIMUM_VERSION([$1],m4_bregexp($2,[\\([0-9]*\\)\\ .*],[\\1]))\nm4_warn([obsolete], [The `NE_REQUIRE_VERSIONS` macro is obsolete.\nUpdate to use `NE_MINIMUM_VERSION`])\n])\n\ndnl Check that the external library found in a given location\ndnl matches the min. required version (if any).  Requires that\ndnl NEON_CONFIG be set the the full path of a valid neon-config\ndnl script\ndnl\ndnl Usage:\ndnl    NEON_CHECK_VERSION(ACTIONS-IF-OKAY, ACTIONS-IF-FAILURE)\ndnl\nAC_DEFUN([NEON_CHECK_VERSION], [\nne_libver=`$NEON_CONFIG --version | sed -e \"s/neon //g\"`\nm4_ifdef([ne_require_major], [\n    # Check whether the library is of required version\n    ne_save_LIBS=\"$LIBS\"\n    ne_save_CFLAGS=\"$CFLAGS\"\n    CFLAGS=\"$CFLAGS `$NEON_CONFIG --cflags`\"\n    LIBS=\"$LIBS `$NEON_CONFIG --libs`\"\n    # Check whether it's possible to link against neon\n    AC_CACHE_CHECK([linking against neon], [ne_cv_lib_neon],\n    [AC_LINK_IFELSE(\n        [AC_LANG_PROGRAM([[#include <ne_utils.h>]], [[ne_version_match(0, 0);]])],\n\t[ne_cv_lib_neon=yes], [ne_cv_lib_neon=no])])\n    if test \"$ne_cv_lib_neon\" = \"yes\"; then\n       ne_libmajor=`echo $ne_libver | sed 's/\\..*//g'`\n       ne_libminor=`echo $ne_libver | sed 's/.*\\.\\([[0-9]]*\\)\\..*/\\1/g'`\n       ne_cv_lib_neonver=no\n       AC_MSG_NOTICE([found neon library version ${ne_libmajor}.${ne_libminor}.x, required ne_require_major[.]ne_require_minor[.x]])\n       # neon 1.x maintains backwards compat to neon 0.27.x\n       if test ne_require_major -eq 0 -a ne_require_minor -ge 27 \\\n          -a $ne_libmajor = 1; then\n          ne_cv_lib_neonver=yes\n       elif test $ne_libmajor -eq ne_require_major \\\n            -a $ne_libminor -ge ne_require_minor; then\n          ne_cv_lib_neonver=yes\n       fi\n    fi\n    ne_goodver=$ne_cv_lib_neonver\n    LIBS=$ne_save_LIBS\n    CFLAGS=$ne_save_CFLAGS\n], [\n    dnl NE_REQUIRE_VERSIONS/NE_MINIMUM_VERSION not used; anything goes.\n    ne_goodver=yes\n])\n\nif test \"$ne_goodver\" = \"yes\"; then\n    AC_MSG_NOTICE([using neon library $ne_libver])\n    $1\nelse\n    AC_MSG_NOTICE([incompatible neon library version $ne_libver: minimum required ne_require_major.ne_require_minor])\n    $2\nfi])\n\ndnl NEON_CHECK_SUPPORT(feature, var, name)\nAC_DEFUN([NEON_CHECK_SUPPORT], [\nif $NEON_CONFIG --support $1 >/dev/null; then\n   NE_ENABLE_SUPPORT($2, [$3 is supported by neon])\nelse\n   NE_DISABLE_SUPPORT($2, [$3 is not supported by neon])\nfi\n])\n\ndnl enable support for feature $1 with define NE_HAVE_$1, message $2\nAC_DEFUN([NE_ENABLE_SUPPORT], [\nNE_FLAG_$1=yes\nAC_SUBST(NE_FLAG_$1)\nAC_DEFINE([NE_HAVE_]$1, 1, [Defined if $1 is supported])\nm4_if([$2], [], \n [ne_$1_message=\"support enabled\"\n  AC_MSG_NOTICE([$1 support is enabled])],\n [ne_$1_message=\"$2\"\n  AC_MSG_NOTICE([$2])])\n])\n\ndnl Disable support for feature $1, giving message $2\nAC_DEFUN([NE_DISABLE_SUPPORT], [\nNE_FLAG_$1=no\nAC_SUBST(NE_FLAG_$1)\nm4_if([$2], [],\n [ne_$1_message=\"not supported\"\n  AC_MSG_NOTICE([$1 support is not enabled])],\n [ne_$1_message=\"$2\"\n  AC_MSG_NOTICE([$2])])\n])\n\nAC_DEFUN([NEON_USE_EXTERNAL], [\n# Configure to use an external neon, given a neon-config script\n# found at $NEON_CONFIG.\nneon_prefix=`$NEON_CONFIG --prefix`\nNEON_CHECK_VERSION([\n    # Pick up CFLAGS and LIBS needed\n    CFLAGS=\"$CFLAGS `$NEON_CONFIG --cflags`\"\n    NEON_LIBS=\"$NEON_LIBS `$NEON_CONFIG --libs`\"\n    # Pick up library version\n    set dummy `$NEON_CONFIG --version | sed 's/\\./ /g'`\n    NE_VERSION_MAJOR=[$]3; NE_VERSION_MINOR=[$]4; NE_VERSION_PATCH=[$]5\n    NE_DEFINE_VERSIONS\n    neon_library_message=\"library in ${neon_prefix} (${NEON_VERSION})\"\n    neon_xml_parser_message=\"using whatever neon uses\"\n    NEON_CHECK_SUPPORT([i18n], [I18N], [Internationalization])\n    NEON_CHECK_SUPPORT([dav], [DAV], [WebDAV])\n    NEON_CHECK_SUPPORT([gssapi], [GSSAPI], [GSSAPI])\n    NEON_CHECK_SUPPORT([libpxy], [LIBPXY], [libproxy])\n    NEON_CHECK_SUPPORT([ssl], [SSL], [SSL])\n    NEON_CHECK_SUPPORT([zlib], [ZLIB], [zlib])\n    NEON_CHECK_SUPPORT([ipv6], [IPV6], [IPv6])\n    NEON_CHECK_SUPPORT([lfs], [LFS], [LFS])\n    NEON_CHECK_SUPPORT([ts_ssl], [TS_SSL], [thread-safe SSL])\n    neon_got_library=yes\n    if test $NE_FLAG_LFS = yes; then\n       NEON_FORMAT(off64_t)\n       AC_DEFINE_UNQUOTED([NE_FMT_NE_OFF_T], [NE_FMT_OFF64_T], \n            [Define to be printf format string for ne_off_t])\n    else\n       AC_DEFINE_UNQUOTED([NE_FMT_NE_OFF_T], [NE_FMT_OFF_T])\n    fi\n], [neon_got_library=no])\n])\n\nAC_DEFUN([NEON_COMMON],[\n\nAC_REQUIRE([NEON_COMMON_CHECKS])\n\nAC_ARG_WITH(neon,\n[  --with-neon[[=DIR]]       specify location of neon library],\n[case $withval in\nyes|no) neon_force_external=$withval; neon_ext_path= ;;\n*) neon_force_external=yes; neon_ext_path=$withval ;;\nesac;], [\nneon_force_external=no\nneon_ext_path=\n])\n\nif test \"$neon_force_included\" = \"no\"; then\n    # There is no included neon source directory, or --with-included-neon\n    # wasn't given (so we're not forced to use it).\n\n    # Default to no external neon.\n    neon_got_library=no\n    if test \"x$neon_ext_path\" = \"x\"; then\n\tAC_PATH_PROG([NEON_CONFIG], neon-config, none)\n\tif test \"x${NEON_CONFIG}\" = \"xnone\"; then\n\t    AC_MSG_NOTICE([no external neon library found])\n\telif test -x \"${NEON_CONFIG}\"; then\n\t    NEON_USE_EXTERNAL\n\telse\n\t    AC_MSG_NOTICE([ignoring non-executable ${NEON_CONFIG}])\n\tfi\n    else\n\tAC_MSG_CHECKING([for neon library in $neon_ext_path])\n\tNEON_CONFIG=\"$neon_ext_path/bin/neon-config\"\n\tif test -x ${NEON_CONFIG}; then\n\t    AC_MSG_RESULT([found])\n\t    NEON_USE_EXTERNAL\n\telse\n\t    AC_MSG_RESULT([not found])\n\t    # ...will fail since force_external=yes\n\tfi\n    fi\n\n    if test \"$neon_got_library\" = \"no\"; then \n\tif test $neon_force_external = yes; then\n\t    AC_MSG_ERROR([could not use external neon library])\n\telif test -n \"$neon_bundled_srcdir\"; then\n\t    # Couldn't find external neon, forced to use bundled sources\n\t    neon_force_included=\"yes\"\n\telse\n\t    # Couldn't find neon, and don't have bundled sources\n\t    AC_MSG_ERROR(could not find neon)\n\tfi\n    fi\nfi\n\nif test \"$neon_force_included\" = \"yes\"; then\n    NE_VERSIONS_BUNDLED\n    AC_MSG_NOTICE([using bundled neon ($NEON_VERSION)])\n    NEON_BUILD_BUNDLED=\"yes\"\n    LIBNEON_SOURCE_CHECKS\n    CFLAGS=\"$CFLAGS -I$neon_bundled_srcdir\"\n    NEON_LIBS=\"-L$neon_bundled_builddir -lneon $NEON_LIBS\"\n    NEON_NEED_XML_PARSER=yes\n    neon_library_message=\"included libneon (${NEON_VERSION})\"\nelse\n    # Don't need to configure an XML parser\n    NEON_NEED_XML_PARSER=no\n    NEON_BUILD_BUNDLED=no\nfi\n\nAC_SUBST(NEON_BUILD_BUNDLED)\n\ndnl Define NE_MINIMUM_VERSION() for both bundled and non-bundled\ndnl builds.\nAH_BOTTOM([#undef NE_MINIMUM_VERSION\n#define NE_MINIMUM_VERSION(majv_, minv_) \\\n    (((majv_) == NE_VERSION_MAJOR && NE_VERSION_MINOR >= (minv_)) \\\n     || NE_VERSION_MAJOR > (majv_))\n])\n\n])\n\ndnl AC_SEARCH_LIBS done differently. Usage:\ndnl   NE_SEARCH_LIBS(function, libnames, [extralibs], [actions-if-not-found],\ndnl                            [actions-if-found])\ndnl Tries to find 'function' by linking against `-lLIB $NEON_LIBS' for each\ndnl LIB in libnames.  If link fails and 'extralibs' is given, will also\ndnl try linking against `-lLIB extralibs $NEON_LIBS`.\ndnl Once link succeeds, `-lLIB [extralibs]` is prepended to $NEON_LIBS, and\ndnl `actions-if-found' are executed, if given.\ndnl If link never succeeds, run `actions-if-not-found', if given, else\ndnl give an error and fail configure.\nAC_DEFUN([NE_SEARCH_LIBS], [\n\nAC_REQUIRE([NE_CHECK_OS])\n\nAC_CACHE_CHECK([for library containing $1], [ne_cv_libsfor_$1], [\n  case $ne_cv_os_uname in\n  MINGW*|MSYS_NT*)\n    ;;\n  *)\n    case $1 in\n    getaddrinfo)\n      ne__prologue=\"#include <netdb.h>\"\n      ne__code=\"getaddrinfo(0,0,0,0);\"\n      ;;\n    socket)\n      ne__prologue=\"#include <sys/socket.h>\"\n      ne__code=\"socket(0,0,0);\"\n      ;;\n    bindtextdomain)\n      ne__prologue=\"#include <libintl.h>\"\n      ne__code=\"bindtextdomain(\\\"\\\",\\\"\\\");\"\n      ;;\n    gethostbyname)\n      ne__prologue=\"#include <netdb.h>\"\n      ne__code=\"gethostbyname(\\\"\\\");\"\n      ;;\n    *)\n      ne__prologue=\"\"\n      ne__code=\"$1();\"\n      ;;\n    esac\n    ;;\n  esac\n  AC_LINK_IFELSE([AC_LANG_PROGRAM([$ne__prologue], [$ne__code])], [ne_cv_libsfor_$1=\"none needed\"], [\n    ne_sl_save_LIBS=$LIBS\n    ne_cv_libsfor_$1=\"not found\"\n    for lib in $2; do\n      case $ne_cv_os_uname in\n      MINGW*|MSYS_NT*)\n        case $lib in\n        ws2_32)\n          ne__prologue=\"#include <winsock2.h>\"\n          case $1 in\n          gethostbyname)\n            ne__code=\"gethostbyname(\\\"\\\")\"\n            ;;\n          socket)\n            ne__code=\"socket(0,0,0);\"\n            ;;\n          *)\n            ne__code=\"$1();\"\n            ;;\n          esac\n          ;;\n        *)\n          ne__prologue=\"\"\n          ne__code=\"\"\n          ;;\n        esac\n        ;;\n      *)\n        ;;\n      esac\n      LIBS=\"$ne_sl_save_LIBS -l$lib $NEON_LIBS\"\n      AC_LINK_IFELSE([AC_LANG_PROGRAM([$ne__prologue], [$ne__code])],\n                     [ne_cv_libsfor_$1=\"-l$lib\"; break])\n      m4_if($3, [], [], dnl If $3 is specified, then...\n                [LIBS=\"$ne_sl_save_LIBS -l$lib $3 $NEON_LIBS\"\n                 AC_LINK_IFELSE([AC_LANG_PROGRAM([$ne__prologue], [$ne__code])],\n                                [ne_cv_libsfor_$1=\"-l$lib $3\"; break])])\n    done\n    LIBS=$ne_sl_save_LIBS\n  ])\n])\nAC_CHECK_HEADERS([wspiapi.h])\n\nif test \"$ne_cv_libsfor_$1\" = \"not found\"; then\n   m4_if([$4], [], [AC_MSG_ERROR([could not find library containing $1])], [$4])\nelif test \"$ne_cv_libsfor_$1\" = \"none needed\"; then\n   m4_if([$5], [], [:], [$5])\nelse\n   NEON_LIBS=\"$ne_cv_libsfor_$1 $NEON_LIBS\"\n   $5\nfi])\n\ndnl Check for presence and suitability of zlib library\nAC_DEFUN([NEON_ZLIB], [\n\nAC_ARG_WITH(zlib, AS_HELP_STRING([--without-zlib], [disable zlib support]),\nne_use_zlib=$withval, ne_use_zlib=yes)\n\nif test \"$ne_use_zlib\" = \"yes\"; then\n    AC_CHECK_HEADER(zlib.h, [\n  \tAC_CHECK_LIB(z, inflate, [ \n\t    NEON_LIBS=\"$NEON_LIBS -lz\"\n            NE_ENABLE_SUPPORT(ZLIB, [zlib support enabled, using -lz])\n\t], [NE_DISABLE_SUPPORT(ZLIB, [zlib library not found])])\n    ], [NE_DISABLE_SUPPORT(ZLIB, [zlib header not found])])\nelse\n    NE_DISABLE_SUPPORT(ZLIB, [zlib not enabled])\nfi\n])\n\nAC_DEFUN([NE_CHECK_OS], [\n# Check for Darwin, which needs extra cpp and linker flags.\nAC_CACHE_CHECK([for uname], ne_cv_os_uname, [\n ne_cv_os_uname=`uname -s 2>/dev/null`\n dnl # Check with autoconf cross-build request, particularly the\n dnl # \"host\" (system type where build program will be executed)\n dnl # NOTE: Quick-and-dirty approach to handle building libneon\n dnl # for Windows using Linux environments with mingw packages:\n dnl # other code in this script checks for \"MINGW*\" matches.\n dnl #  ./configure --prefix=/usr/i686-w64-mingw32 --host=i686-w64-mingw32 PKG_CONFIG_PATH=/usr/i686-w64-mingw32/lib/pkgconfig\n case x\"$host\" in\n    x*mingw*) ne_cv_os_uname=\"MINGW-$host\" ;;\n esac\n])\n\nAS_CASE([x\"$ne_cv_os_uname\"],\n[x\"Darwin\"], [\n  CPPFLAGS=\"$CPPFLAGS -no-cpp-precomp\"\n  LDFLAGS=\"$LDFLAGS -flat_namespace\" \n  # poll has various issues in various Darwin releases\n  if test x${ac_cv_func_poll+set} != xset; then\n    ac_cv_func_poll=no\n  fi\n],\n[xMINGW*|xMSYS*],\n  [NEON_LIBS=\"$NEON_LIBS -lws2_32\"]\n)dnl AS_CASE\n])\n\nAC_DEFUN([NE_FORMAT_TIMET], [\nNEON_FORMAT(time_t, [\n#ifdef HAVE_SYS_TIME_H\n#include <sys/time.h>\n#endif])\n])\n\nAC_DEFUN([NEON_COMMON_CHECKS], [\n\n# These checks are done whether or not the bundled neon build\n# is used.\n\nifdef([AC_USE_SYSTEM_EXTENSIONS], \n[AC_USE_SYSTEM_EXTENSIONS],\n[AC_ISC_POSIX])\nAC_REQUIRE([AC_PROG_CC])\nAC_REQUIRE([AC_C_INLINE])\nAC_REQUIRE([AC_C_CONST])\nAC_REQUIRE([AC_TYPE_SIZE_T])\nAC_REQUIRE([AC_TYPE_OFF_T])\n\nAC_REQUIRE([NE_CHECK_OS])\n\nAC_REQUIRE([AC_PROG_MAKE_SET])\n\nAC_CHECK_HEADERS([errno.h stdarg.h string.h stdlib.h sys/uio.h])\n\nNEON_FORMAT(size_t,,u) dnl size_t is unsigned; use %u formats\nNEON_FORMAT(off_t)\nNEON_FORMAT(ssize_t)\nNE_FORMAT_TIMET\n])\n\nAC_DEFUN([NEON_FORMAT_PREP], [\nAC_CHECK_SIZEOF(int)\nAC_CHECK_SIZEOF(long)\nAC_CHECK_SIZEOF(long long)\nif test \"$GCC\" = \"yes\"; then\n  AC_CACHE_CHECK([for gcc -Wformat -Werror sanity], ne_cv_cc_werror, [\n  # See whether a simple test program will compile without errors.\n  ne_save_CPPFLAGS=$CPPFLAGS\n  CPPFLAGS=\"$CPPFLAGS -Wformat -Werror\"\n  AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/types.h>\n#include <stdio.h>]], [[int i = 42; printf(\"%d\", i);]])],\n  [ne_cv_cc_werror=yes], [ne_cv_cc_werror=no])\n  CPPFLAGS=$ne_save_CPPFLAGS])\n  ne_fmt_trycompile=$ne_cv_cc_werror\nelse\n  ne_fmt_trycompile=no\nfi\n])\n\ndnl Check for LFS support\nAC_DEFUN([NE_LARGEFILE], [\ndnl Need the size of off_t\nAC_REQUIRE([NEON_COMMON_CHECKS])\n\nif test -z \"$ac_cv_sizeof_off_t\"; then\n   NE_DISABLE_SUPPORT(LFS, [LFS support omitted: off_t size unknown!])\nelif test $ac_cv_sizeof_off_t != 4; then\n   NE_DISABLE_SUPPORT(LFS, [LFS support unnecessary, off_t is not 32-bit])\n   AC_CHECK_FUNCS([strtoll strtoq], [break])\nelif test -z \"$ac_cv_sizeof_long_long\"; then\n   NE_DISABLE_SUPPORT(LFS, [LFS support omitted: long long size unknown])\nelif test $ac_cv_sizeof_long_long != 8; then\n   NE_DISABLE_SUPPORT(LFS, [LFS support omitted: long long not 64-bit])\nelse\n   ne_save_CPPFLAGS=$CPPFLAGS\n   CPPFLAGS=\"$CPPFLAGS -D_LARGEFILE64_SOURCE\"\n   AC_CHECK_TYPE(off64_t, [\n     NEON_FORMAT(off64_t)\n     ne_lfsok=no\n     AC_CHECK_FUNCS([strtoll strtoq], [ne_lfsok=yes; break])\n     AS_CASE([$ne_cv_os_uname],\n       [MINGW*|MSYS_NT*],\n         [AC_CHECK_FUNCS([lseek64], [], [ne_lfsok=no; break])],\n       dnl Default:\n         [AC_CHECK_FUNCS([lseek64 fstat64], [], [ne_lfsok=no; break])]\n     )\n     if test x$ne_lfsok = xyes; then\n       NE_ENABLE_SUPPORT(LFS, [LFS (large file) support enabled])\n       NEON_CFLAGS=\"$NEON_CFLAGS -D_LARGEFILE64_SOURCE -DNE_LFS\"\n       ne_save_CPPFLAGS=\"$CPPFLAGS -DNE_LFS\"\n     else\n       NE_DISABLE_SUPPORT(LFS, \n         [LFS support omitted: 64-bit support functions not found])\n     fi], [NE_DISABLE_SUPPORT(LFS, [LFS support omitted: off64_t type not found])])\n   CPPFLAGS=$ne_save_CPPFLAGS\nfi\nif test \"$NE_FLAG_LFS\" = \"yes\"; then\n   AC_DEFINE_UNQUOTED([NE_FMT_NE_OFF_T], [NE_FMT_OFF64_T], \n                      [Define to be printf format string for ne_off_t])\n   NE_ADD_ABITAG(LFS)\nelse\n   AC_DEFINE_UNQUOTED([NE_FMT_NE_OFF_T], [NE_FMT_OFF_T])\nfi\n])\n\ndnl NEON_FORMAT(TYPE[, HEADERS[, [SPECIFIER]])\ndnl\ndnl This macro finds out which modifier is needed to create a\ndnl printf format string suitable for printing integer type TYPE (which\ndnl may be an int, long, or long long).\ndnl The default specifier is 'd', if SPECIFIER is not given.  \ndnl TYPE may be defined in HEADERS; sys/types.h is always used first.\nAC_DEFUN([NEON_FORMAT], [\n\nAC_REQUIRE([NEON_FORMAT_PREP])\n\nAC_CHECK_SIZEOF($1,, [AC_INCLUDES_DEFAULT\n$2])\n\ndnl Work out which specifier character to use\nm4_ifdef([ne_spec], [m4_undefine([ne_spec])])\nm4_if($#, 3, [m4_define(ne_spec,$3)], [m4_define(ne_spec,d)])\n\nm4_ifdef([ne_cvar], [m4_undefine([ne_cvar])])dnl\nm4_define([ne_cvar], m4_translit(ne_cv_fmt_[$1], [ ], [_]))dnl\n\nAC_CACHE_CHECK([how to print $1], [ne_cvar], [\nne_cvar=none\nif test $ne_fmt_trycompile = yes; then\n  oflags=\"$CPPFLAGS\"\n  # Consider format string mismatches as errors\n  CPPFLAGS=\"$CPPFLAGS -Wformat -Werror\"\n  dnl obscured for m4 quoting: \"for str in d ld lld; do\"\n  for str in ne_spec l]ne_spec[ ll]ne_spec[; do\n    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/types.h>\n$2\n#include <stdio.h>]], [[$1 i = 1; printf(\"%$str\", i);]])],\n\t[ne_cvar=$str; break])\n  done\n  CPPFLAGS=$oflags\nelse\n  # Best guess. Don't have to be too precise since we probably won't\n  # get a warning message anyway.\n  case $ac_cv_sizeof_]m4_translit($1, [ ], [_])[ in\n  $ac_cv_sizeof_int) ne_cvar=\"ne_spec\" ;;\n  $ac_cv_sizeof_long) ne_cvar=\"l]ne_spec[\" ;;\n  $ac_cv_sizeof_long_long) ne_cvar=\"ll]ne_spec[\" ;;\n  esac\nfi\n])\n\nif test \"x$ne_cvar\" = \"xnone\"; then\n  AC_MSG_ERROR([format string for $1 not found])\nfi\n\nAC_DEFINE_UNQUOTED([NE_FMT_]m4_translit($1, [a-z ], [A-Z_]), \"$ne_cvar\", \n\t[Define to be printf format string for $1])\n])\n\ndnl Wrapper for AC_CHECK_FUNCS; uses libraries from $NEON_LIBS.\nAC_DEFUN([NE_CHECK_FUNCS], [\nne_cf_save_LIBS=$LIBS\nLIBS=\"$LIBS $NEON_LIBS\"\nAC_CHECK_FUNCS($@)\nLIBS=$ne_cf_save_LIBS])\n\ndnl Checks needed when compiling the neon source.\nAC_DEFUN([LIBNEON_SOURCE_CHECKS], [\n\ndnl Run all the normal C language/compiler tests\nAC_REQUIRE([NEON_COMMON_CHECKS])\n\ndnl Needed for building the MD5 code.\nAC_REQUIRE([AC_C_BIGENDIAN])\ndnl Is strerror_r present; if so, which variant\nAC_REQUIRE([AC_FUNC_STRERROR_R])\n\nAC_CHECK_HEADERS([sys/time.h limits.h sys/select.h arpa/inet.h libintl.h \\\n\tsignal.h sys/socket.h netinet/in.h netinet/tcp.h netdb.h sys/poll.h \\\n\tsys/limits.h fcntl.h iconv.h net/if.h],,,\n[AC_INCLUDES_DEFAULT\n/* netinet/tcp.h requires netinet/in.h on some platforms. */\n#ifdef HAVE_NETINET_IN_H\n#include <netinet/in.h>\n#endif])\n\nAC_REQUIRE([NE_SNPRINTF])\n\nAC_CACHE_CHECK([for timezone global], ne_cv_cc_timezone, [\nAC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <sys/types.h>\n#include <time.h>]],\n[[time_t t = 0 - timezone; timezone = 1;]])],\nne_cv_cc_timezone=yes, ne_cv_cc_timezone=no)])\n\nif test \"$ne_cv_cc_timezone\" = \"yes\"; then\n   AC_DEFINE([HAVE_TIMEZONE], 1, [Define if the timezone global is available])\nfi\n\ndnl Check for large file support\nNE_LARGEFILE\n\nAC_REPLACE_FUNCS(strcasecmp)\n\nAC_CHECK_FUNCS([signal setvbuf setsockopt stpcpy poll fcntl getsockopt \\\n                explicit_bzero sendmsg gettimeofday gmtime_r getrandom])\n\nif test \"x${ac_cv_func_poll}${ac_cv_header_sys_poll_h}y\" = \"xyesyesy\"; then\n  AC_DEFINE([NE_USE_POLL], 1, [Define if poll() should be used])\nfi\n\nif test \"$ac_cv_func_stpcpy\" = \"yes\"; then\n  AC_CHECK_DECLS(stpcpy)\nfi\n\n# Modern AIXes with the \"Linux-like\" libc have an undeclared stpcpy\nAH_BOTTOM([#if defined(HAVE_STPCPY) && defined(HAVE_DECL_STPCPY) && !HAVE_DECL_STPCPY && !defined(stpcpy)\nchar *stpcpy(char *, const char *);\n#endif])\n\n# Unixware 7 can only link gethostbyname with -lnsl -lsocket\n# Pick up -lsocket first, then the gethostbyname check will work.\n# Haiku requires -lnetwork for socket functions.\nNE_SEARCH_LIBS(socket, socket inet ws2_32 network)\n\n# Enable getaddrinfo support if it, gai_strerror and inet_ntop are\n# all available.\nNE_SEARCH_LIBS(getaddrinfo, nsl,,\n  [ne_enable_gai=no],\n  [# HP-UX boxes commonly get into a state where getaddrinfo is present\n   # but borked: http://marc.theaimsgroup.com/?l=apr-dev&m=107730955207120&w=2\n   case x`uname -sr 2>/dev/null`y in\n   xHP-UX*11.[[01]]*y)\n      AC_MSG_NOTICE([getaddrinfo support disabled on HP-UX 11.0x/11.1x]) ;;\n   *)\n     ne_enable_gai=yes\n     NE_CHECK_FUNCS(gai_strerror getnameinfo inet_ntop inet_pton,,\n                    [ne_enable_gai=no; break]) ;;\n   esac\n])\n\nif test $ne_enable_gai = yes; then\n   NE_ENABLE_SUPPORT(IPV6, [IPv6 support is enabled])\n   NE_CHECK_FUNCS([if_nametoindex if_indextoname])\n   AC_DEFINE(USE_GETADDRINFO, 1, [Define if getaddrinfo() should be used])\n   AC_CACHE_CHECK([for working AI_ADDRCONFIG], [ne_cv_gai_addrconfig], [\n   AC_RUN_IFELSE([AC_LANG_PROGRAM([#include <netdb.h>\n#include <stdlib.h>],\n[struct addrinfo hints = {0}, *result;\nhints.ai_flags = AI_ADDRCONFIG;\nif (getaddrinfo(\"localhost\", NULL, &hints, &result) != 0) return 1;])],\n   ne_cv_gai_addrconfig=yes, ne_cv_gai_addrconfig=no, ne_cv_gai_addrconfig=no)])\n   if test $ne_cv_gai_addrconfig = yes; then\n      AC_DEFINE(USE_GAI_ADDRCONFIG, 1, [Define if getaddrinfo supports AI_ADDRCONFIG])\n   fi\nelse\n   # Checks for non-getaddrinfo() based resolver interfaces.\n   # QNX has gethostbyname in -lsocket. BeOS only has it in -lbind.\n   # CygWin/Winsock2 has it in -lws2_32, allegedly.\n   # Haiku requires -lnetwork for socket functions.\n   NE_SEARCH_LIBS(gethostbyname, socket nsl bind ws2_32 network)\n   NE_SEARCH_LIBS(hstrerror, resolv,,[:])\n   NE_CHECK_FUNCS(hstrerror)\n   # Older Unixes don't declare h_errno.\n   AC_CHECK_DECLS(h_errno,,,[#include <netdb.h>])\n   AC_CHECK_TYPE(in_addr_t,,[\n     AC_DEFINE([in_addr_t], [unsigned int], \n                            [Define if in_addr_t is not available])], [\n#ifdef HAVE_SYS_TYPES_H\n# include <sys/types.h>\n#endif\n#ifdef HAVE_NETINET_IN_H\n# include <netinet/in.h>\n#endif\n])\nfi\n\nAC_CHECK_TYPES(socklen_t,,\n# Linux accept(2) says this should be size_t for SunOS 5... gah.\n[AC_DEFINE([socklen_t], [int], \n                        [Define if socklen_t is not available])],[\n#ifdef HAVE_SYS_TYPES_H\n# include <sys/types.h>\n#endif\n#ifdef HAVE_SYS_SOCKET_H\n# include <sys/socket.h>\n#endif\n#ifdef _WIN32\n# include <ws2tcpip.h>\n#endif\n])\n\nAC_CHECK_MEMBERS([struct tm.tm_gmtoff, struct tm.__tm_gmtoff],,,\n  [#include <time.h>])\n\nif test ${ac_cv_member_struct_tm_tm_gmtoff}${ac_cv_member_struct_tm___tm_gmtoff}${ne_cv_cc_timezone} = nonono; then\n  AC_MSG_WARN([no timezone handling in date parsing on this platform])\nfi\n\nifdef([neon_no_zlib], \n  [NE_DISABLE_SUPPORT(ZLIB, [zlib not supported])],\n  [NEON_ZLIB()])\n\n# Conditionally enable ACL support\nAC_MSG_CHECKING([whether to enable ACL support in neon])\nif test \"x$neon_no_acl\" = \"xyes\"; then\n    AC_MSG_RESULT(no)\nelse\n    AC_MSG_RESULT(yes)\n    NEON_EXTRAOBJS=\"$NEON_EXTRAOBJS ne_oldacl ne_acl3744\"\nfi\n\nNEON_SSL()\nNEON_GSSAPI()\nNEON_NTLM()\nNEON_LIBPROXY()\n\nAC_SUBST(NEON_CFLAGS)\nAC_SUBST(NEON_LIBS)\nAC_SUBST(NEON_LTLIBS)\n\n])\n\ndnl Call to put lib/snprintf.o in LIBOBJS and define HAVE_SNPRINTF_H\ndnl if snprintf isn't in libc.\n\nAC_DEFUN([NEON_REPLACE_SNPRINTF], [\n# Check for snprintf\nAC_CHECK_FUNC(snprintf,,[\n\tAC_DEFINE(HAVE_SNPRINTF_H, 1, [Define if need to include snprintf.h])\n\tAC_LIBOBJ(lib/snprintf)])\n])\n\ndnl turn off webdav, boo hoo.\nAC_DEFUN([NEON_WITHOUT_WEBDAV], [\nneon_no_webdav=yes\nneon_no_acl=yes\nNEON_NEED_XML_PARSER=no\nneon_xml_parser_message=\"none needed\"\n])\n\ndnl Turn off zlib support\nAC_DEFUN([NEON_WITHOUT_ZLIB], [\ndefine(neon_no_zlib, yes)\n])\n\nAC_DEFUN([NEON_WITHOUT_ACL], [\n# Turn off ACL support\nneon_no_acl=yes\n])\n\ndnl Common macro to NEON_LIBTOOL_BUILD and NEON_NORMAL_BUILD\ndnl Sets NEONOBJS appropriately if it has not already been set.\ndnl \ndnl NOT FOR EXTERNAL USE: use LIBTOOL_BUILD or NORMAL_BUILD.\ndnl\n\nAC_DEFUN([NEON_COMMON_BUILD], [\n\n# Using the default set of object files to build.\n# Add the extension to EXTRAOBJS\nne=\"$NEON_EXTRAOBJS\"\nNEON_EXTRAOBJS=\nfor o in $ne; do\n\tNEON_EXTRAOBJS=\"$NEON_EXTRAOBJS $o.$NEON_OBJEXT\"\ndone\n\n# Was DAV support explicitly turned off?\nif test \"x$neon_no_webdav\" = \"xyes\"; then\n  # No WebDAV support\n  NEONOBJS=\"$NEONOBJS \\$(NEON_BASEOBJS)\"\n  NE_DISABLE_SUPPORT(DAV, [WebDAV support is not enabled])\n  NE_ADD_ABITAG(NODAV)\nelse\n  # WebDAV support\n  NEONOBJS=\"$NEONOBJS \\$(NEON_DAVOBJS)\"\n  NE_ENABLE_SUPPORT(DAV, [WebDAV support is enabled])\nfi\n\nAC_SUBST(NEON_TARGET)\nAC_SUBST(NEON_OBJEXT)\nAC_SUBST(NEONOBJS)\nAC_SUBST(NEON_EXTRAOBJS)\nAC_SUBST(NEON_LINK_FLAGS)\n\n])\n\n# The libtoolized build case:\nAC_DEFUN([NEON_LIBTOOL_BUILD], [\n\nNEON_TARGET=libneon.la\nNEON_OBJEXT=lo\n\nNEON_COMMON_BUILD($#, $*)\n\n])\n\ndnl Find 'ar' and 'ranlib', fail if ar isn't found.\nAC_DEFUN([NE_FIND_AR], [\n\n# Search in /usr/ccs/bin for Solaris\nne_PATH=$PATH:/usr/ccs/bin\nAC_CHECK_TOOL(AR, ar, notfound, $ne_PATH)\nif test \"x$AR\" = \"xnotfound\"; then\n   AC_MSG_ERROR([could not find ar tool])\nfi\nAC_CHECK_TOOL(RANLIB, ranlib, :, $ne_PATH)\n\n])\n\n# The non-libtool build case:\nAC_DEFUN([NEON_NORMAL_BUILD], [\n\nNEON_TARGET=libneon.a\nNEON_OBJEXT=o\n\nAC_REQUIRE([NE_FIND_AR])\n\nNEON_COMMON_BUILD($#, $*)\n\n])\n\nAC_DEFUN([NE_SNPRINTF], [\nAC_CHECK_FUNCS(snprintf vsnprintf,,[\n   ne_save_LIBS=$LIBS\n   LIBS=\"$LIBS -lm\"    # Always need -lm\n   AC_CHECK_LIB(trio, trio_vsnprintf,\n   [AC_CHECK_HEADERS(trio.h,,\n    AC_MSG_ERROR([trio installation problem? libtrio found but not trio.h]))\n    AC_MSG_NOTICE(using trio printf replacement library)\n    NEON_LIBS=\"$NEON_LIBS -ltrio -lm\"\n    AC_DEFINE(HAVE_TRIO, 1, [Use trio printf replacement library])],\n   [AC_MSG_NOTICE([no vsnprintf/snprintf detected in C library])\n    AC_MSG_ERROR([Install the trio library from http://daniel.haxx.se/projects/trio/])])\n   LIBS=$ne_save_LIBS\n   break\n])])\n\ndnl Usage: NE_CHECK_OPENSSLVER(variable, version-string, version-hex)\ndnl Define 'variable' to 'yes' if OpenSSL version is >= version-hex\nAC_DEFUN([NE_CHECK_OPENSSLVER], [\nAC_CACHE_CHECK([OpenSSL version is >= $2], $1, [\nAC_EGREP_CPP(good, [#include <openssl/opensslv.h>\n#if OPENSSL_VERSION_NUMBER >= $3\ngood\n#endif], [$1=yes\n$4], [$1=no])])])\n\ndnl Less noisy replacement for PKG_CHECK_MODULES\nAC_DEFUN([NE_PKG_CONFIG], [\n\nm4_define([ne_cvar], m4_translit(ne_cv_pkg_[$2], [.-], [__]))dnl\n\nAC_PATH_TOOL(PKG_CONFIG, pkg-config, no)\nif test \"x$PKG_CONFIG\" = \"xno\"; then\n   : Not using pkg-config\n   $4\nelse\n   AC_CACHE_CHECK([for $2 pkg-config data], ne_cvar,\n     [if $PKG_CONFIG $2; then\n        ne_cvar=yes\n      else\n        ne_cvar=no\n      fi])\n\n   if test \"$ne_cvar\" = \"yes\"; then\n      $1_CFLAGS=`$PKG_CONFIG --cflags $2`\n      $1_LIBS=`$PKG_CONFIG --libs $2`\n      $1_VERSION=`$PKG_CONFIG --modversion $2`\n      : Using provided pkg-config data\n      $3\n   else\n      : No pkg-config for $2 provided\n      $4\n   fi\nfi\n\nm4_undefine([ne_cvar])\n])\n\ndnl Check for an SSL library (GNU TLS or OpenSSL)\nAC_DEFUN([NEON_SSL], [\n\nAC_ARG_WITH(ssl,\n            AS_HELP_STRING([--with-ssl=openssl|gnutls],\n                           [enable SSL support (default OpenSSL)]))\n\nAC_ARG_WITH(egd,\n[[  --with-egd[=PATH]       enable EGD support [using EGD socket at PATH]]])\n\nAC_ARG_WITH(pakchois,\n            AS_HELP_STRING([--without-pakchois],\n                           [disable support for PKCS#11 using pakchois]))\n\ncase $with_ssl in\n/*)\n   AC_MSG_NOTICE([to use SSL libraries in non-standard locations, try --with-ssl --with-libs=$with_ssl])\n   AC_MSG_ERROR([--with-ssl does not take a path argument])\n   ;;\nyes|openssl)\n   NE_PKG_CONFIG(NE_SSL, openssl,\n    [AC_MSG_NOTICE(using OpenSSL $NE_SSL_VERSION library configuration from pkg-config)\n     CPPFLAGS=\"$CPPFLAGS ${NE_SSL_CFLAGS}\"\n     NEON_LIBS=\"$NEON_LIBS ${NE_SSL_LIBS}\"],\n    [# Either OpenSSL library may require -ldl if built with dynamic engine support\n     NE_SEARCH_LIBS(RSA_new, crypto, -ldl)\n     NE_SEARCH_LIBS(SSL_library_init, ssl, -ldl)\n     NE_SSL_VERSION=\"(0.9.7 or later)\"])\n\n   AC_CHECK_HEADERS(openssl/ssl.h openssl/opensslv.h,,\n   [AC_MSG_ERROR([OpenSSL headers not found, cannot enable SSL support])])\n\n   NE_CHECK_OPENSSLVER(ne_cv_lib_ssl097, 0.9.7, 0x00907000L)\n   NE_CHECK_OPENSSLVER(ne_cv_lib_ssl110, 1.1.0, 0x10100000L)\n   NE_CHECK_FUNCS(SSL_CIPHER_standard_name ASN1_TIME_to_tm timegm)\n   if test \"$ne_cv_lib_ssl110\" = \"yes\"; then\n      NE_ENABLE_SUPPORT(SSL, [SSL support enabled, using OpenSSL $NE_SSL_VERSION])\n      AC_DEFINE(HAVE_OPENSSL11, 1, [Enable OpenSSL 1.1 support])\n   elif test \"$ne_cv_lib_ssl097\" = \"yes\"; then\n      # Enable EGD support if using 0.9.7 or newer\n      AC_MSG_NOTICE([OpenSSL >= 0.9.7; EGD support not needed in neon])\n      NE_ENABLE_SUPPORT(SSL, [SSL support enabled, using OpenSSL $NE_SSL_VERSION])\n      NE_CHECK_FUNCS(CRYPTO_set_idptr_callback SSL_SESSION_cmp)\n   else\n      # Fail if OpenSSL is older than 0.9.6\n      NE_CHECK_OPENSSLVER(ne_cv_lib_ssl096, 0.9.6, 0x00906000L)\n      if test \"$ne_cv_lib_ssl096\" != \"yes\"; then\n         AC_MSG_ERROR([OpenSSL 0.9.6 or later is required])\n      fi\n      NE_ENABLE_SUPPORT(SSL, [SSL support enabled, using OpenSSL (0.9.6 or later)])\n\n      case \"$with_egd\" in\n      yes|no) ne_cv_lib_sslegd=$with_egd ;;\n      /*) ne_cv_lib_sslegd=yes\n          AC_DEFINE_UNQUOTED([EGD_PATH], \"$with_egd\", \n\t\t\t     [Define to specific EGD socket path]) ;;\n      *) # Guess whether EGD support is needed\n         AC_CACHE_CHECK([whether to enable EGD support], [ne_cv_lib_sslegd],\n\t [if test -r /dev/random || test -r /dev/urandom; then\n\t    ne_cv_lib_sslegd=no\n\t  else\n\t    ne_cv_lib_sslegd=yes\n\t  fi])\n\t ;;\n      esac\n      if test \"$ne_cv_lib_sslegd\" = \"yes\"; then\n        AC_MSG_NOTICE([EGD support enabled for seeding OpenSSL PRNG])\n        AC_DEFINE([ENABLE_EGD], 1, [Define if EGD should be supported])\n      fi\n   fi\n\n   AC_DEFINE([HAVE_OPENSSL], 1, [Define if OpenSSL support is enabled])\n   NEON_EXTRAOBJS=\"$NEON_EXTRAOBJS ne_openssl\"\n   ;;\ngnutls)\n   NE_PKG_CONFIG(NE_SSL, gnutls,\n     [AC_MSG_NOTICE(using GnuTLS configuration from pkg-config)\n      CPPFLAGS=\"$CPPFLAGS ${NE_SSL_CFLAGS}\"\n      NEON_LIBS=\"$NEON_LIBS ${NE_SSL_LIBS}\"\n     ], [\n      # Fall back on libgnutls-config script\n      AC_PATH_PROG(GNUTLS_CONFIG, libgnutls-config, no)\n\n      if test \"$GNUTLS_CONFIG\" = \"no\"; then\n        AC_MSG_ERROR([could not find libgnutls-config in \\$PATH])\n      fi\n\n      CPPFLAGS=\"$CPPFLAGS `$GNUTLS_CONFIG --cflags`\"\n      NEON_LIBS=\"$NEON_LIBS `$GNUTLS_CONFIG --libs`\"\n      NE_SSL_VERSION=\"`$GNUTLS_CONFIG --version`\"\n     ])\n\n   AC_CHECK_HEADER([gnutls/gnutls.h],,\n      [AC_MSG_ERROR([could not find gnutls/gnutls.h in include path])])\n\n   NE_ENABLE_SUPPORT(SSL, [SSL support enabled, using GnuTLS $NE_SSL_VERSION])\n   NEON_EXTRAOBJS=\"$NEON_EXTRAOBJS ne_gnutls\"\n   AC_DEFINE([HAVE_GNUTLS], 1, [Define if GnuTLS support is enabled])\n\n   # Check for functions in later releases\n   NE_CHECK_FUNCS([gnutls_session_get_data2 gnutls_x509_dn_get_rdn_ava \\\n                  gnutls_ciphersuite_get \\\n                  gnutls_certificate_get_issuer \\\n                  gnutls_certificate_get_x509_cas \\\n                  gnutls_x509_crt_sign2 \\\n                  gnutls_x509_crt_equals \\\n                  gnutls_set_default_priority_append \\\n                  gnutls_certificate_set_retrieve_function2 \\\n                  gnutls_certificate_set_x509_system_trust \\\n                  gnutls_privkey_import_ext])\n\n   # fail if gnutls_x509_crt_sign2 is not found (it was introduced in 1.2.0, which is required)\n   if test x${ac_cv_func_gnutls_x509_crt_sign2} != xyes; then\n       AC_MSG_ERROR([GnuTLS version predates gnutls_x509_crt_sign2, newer version required (at least 1.2.0)])\n   fi\n                  \n   # Check for iconv support if using the new RDN access functions:\n   if test ${ac_cv_func_gnutls_x509_dn_get_rdn_ava}X${ac_cv_header_iconv_h} = yesXyes; then\n      AC_CHECK_FUNCS(iconv)\n   fi\n   ;;\n*) # Default to off; only create crypto-enabled binaries if requested.\n   NE_DISABLE_SUPPORT(SSL, [SSL support is not enabled])\n   NE_DISABLE_SUPPORT(TS_SSL, [Thread-safe SSL support is not enabled])\n   NEON_EXTRAOBJS=\"$NEON_EXTRAOBJS ne_stubssl\"\n   ;;\nesac\nAC_SUBST(NEON_SUPPORTS_SSL)\n\nAC_ARG_WITH(ca-bundle, \n  AS_HELP_STRING(--with-ca-bundle, specify filename of an SSL CA root bundle),,\n  with_ca_bundle=no)\n\ncase ${NE_FLAG_SSL}-${with_ca_bundle} in\n*-no) ;;\nyes-*)\n   AC_DEFINE_UNQUOTED([NE_SSL_CA_BUNDLE], [\"${with_ca_bundle}\"],\n                      [Define to be filename of an SSL CA root bundle])\n   AC_MSG_NOTICE([Using ${with_ca_bundle} as default SSL CA bundle])\n   ;;\nesac\n\nAC_ARG_ENABLE(threadsafe-ssl,\nAS_HELP_STRING(--enable-threadsafe-ssl=posix, \n[enable SSL library thread-safety using POSIX threads: suitable\nCC/CFLAGS/LIBS must be used to make the POSIX library interfaces\navailable]),,\nenable_threadsafe_ssl=no)\n\ncase ${enable_threadsafe_ssl}X${ne_cv_lib_ssl110} in\n*Xyes)\n  NE_ENABLE_SUPPORT(TS_SSL, [OpenSSL is natively thread-safe])\n  ;;\nposixX*|yesX*)\n  ne_pthr_ok=yes\n  AC_CHECK_FUNCS([pthread_mutex_init pthread_mutex_lock],,[ne_pthr_ok=no])\n  if test \"${ne_pthr_ok}\" = \"no\"; then\n     AC_MSG_ERROR([could not find POSIX mutex interfaces; (try CC=\"${CC} -pthread\"?)])    \n  fi\n  NE_ENABLE_SUPPORT(TS_SSL, [Thread-safe SSL supported using POSIX threads])\n  ;;\n*)\n  NE_DISABLE_SUPPORT(TS_SSL, [Thread-safe SSL not supported])\n  ;;\nesac\n\ncase ${with_pakchois}X${ac_cv_func_gnutls_privkey_import_ext}Y${ne_cv_lib_ssl097} in\nnoX*Y*) ;;\n*X*Yyes|*XyesY*)\n    # PKCS#11... ho!\n    NE_PKG_CONFIG(NE_PK11, pakchois,\n      [AC_MSG_NOTICE([[using pakchois $NE_PK11_VERSION for PKCS#11 support]])\n       AC_DEFINE(HAVE_PAKCHOIS, 1, [Define if pakchois library supported])\n       CPPFLAGS=\"$CPPFLAGS ${NE_PK11_CFLAGS}\"\n       NEON_LIBS=\"${NEON_LIBS} ${NE_PK11_LIBS}\"],\n      [AC_MSG_NOTICE([[pakchois library not found; no PKCS#11 support]])])\n   ;;\nesac\n]) dnl -- end defun NEON_SSL\n\ndnl Check for Kerberos installation\nAC_DEFUN([NEON_GSSAPI], [\nAC_ARG_WITH(gssapi, AS_HELP_STRING(--without-gssapi, disable GSSAPI support),\n            [need_gssapi=$withval], [need_gssapi=no])\nif test \"$with_gssapi\" != \"no\"; then\n  ne_save_CFLAGS=$CFLAGS\n  ne_save_LIBS=$NEON_LIBS\n  NE_PKG_CONFIG(NE_GSSAPI, [krb5-gssapi],\n    [AC_MSG_NOTICE(using GSSAPI configuration from pkg-config)\n     KRB5_CONF_TOOL=pkgconf],\n    [AC_PATH_PROG([KRB5_CONF_TOOL], krb5-config, none, $PATH:/usr/kerberos/bin)\n     if test \"x$KRB5_CONF_TOOL\" != \"xnone\"; then\n        NE_GSSAPI_LIBS=\"`${KRB5_CONF_TOOL} --libs gssapi`\"\n        NE_GSSAPI_CFLAGS=\"`${KRB5_CONF_TOOL} --cflags gssapi`\"\n        NE_GSSAPI_VERSION=\"`${KRB5_CONF_TOOL} --version`\"\n     fi])\nelse\n  KRB5_CONF_TOOL=none\nfi\nif test \"x$KRB5_CONF_TOOL\" != \"xnone\"; then\n   CFLAGS=\"$CFLAGS ${NE_GSSAPI_CFLAGS}\"\n   NEON_LIBS=\"${NEON_LIBS} ${NE_GSSAPI_LIBS}\"\n   # MIT and Heimdal put gssapi.h in different places\n   AC_CHECK_HEADERS(gssapi/gssapi.h gssapi.h, [\n     NE_CHECK_FUNCS(gss_init_sec_context, [\n      ne_save_CFLAGS=$CFLAGS\n      ne_save_LIBS=$NEON_LIBS\n      NE_ENABLE_SUPPORT(GSSAPI, [GSSAPI support enabled, using library ${NE_GSSAPI_LIBS} version ${NE_GSSAPI_VERSION}])\n      AC_DEFINE(HAVE_GSSAPI, 1, [Define if GSSAPI support is enabled])\n      AC_CHECK_HEADERS(gssapi/gssapi_generic.h)\n      # Older versions of MIT Kerberos lack GSS_C_NT_HOSTBASED_SERVICE\n      AC_CHECK_DECL([GSS_C_NT_HOSTBASED_SERVICE],,\n        [AC_DEFINE([GSS_C_NT_HOSTBASED_SERVICE], gss_nt_service_name, \n          [Define if GSS_C_NT_HOSTBASED_SERVICE is not defined otherwise])],\n        [#ifdef HAVE_GSSAPI_GSSAPI_H\n#include <gssapi/gssapi.h>\n#else\n#include <gssapi.h>\n#endif])])\n     break\n   ])\n   CFLAGS=$ne_save_CFLAGS\n   NEON_LIBS=$ne_save_LIBS\nfi\n\nif test x$NE_FLAG_GSSAPI != xyes; then\n  if test $need_gssapi = yes; then\n    # Fail if --with-gssapi was specified but no library support found\n    AC_MSG_ERROR([could not enable GSSAPI support])\n  fi\n  NE_DISABLE_SUPPORT(GSSAPI, [GSSAPI authentication is not supported])\nfi])\n\nAC_DEFUN([NEON_LIBPROXY], [\nAC_ARG_WITH(libproxy, AS_HELP_STRING(--without-libproxy, disable libproxy support))\nif test \"x$with_libproxy\" != \"xno\"; then\n   NE_PKG_CONFIG(NE_PXY, libproxy-1.0,\n     [AC_DEFINE(HAVE_LIBPROXY, 1, [Define if libproxy is supported])\n      CPPFLAGS=\"$CPPFLAGS $NE_PXY_CFLAGS\"\n      NEON_LIBS=\"$NEON_LIBS ${NE_PXY_LIBS}\"\n      NE_ENABLE_SUPPORT(LIBPXY, [libproxy support enabled using libproxy $NE_PXY_VERSION])],\n     [NE_DISABLE_SUPPORT(LIBPXY, [libproxy support not enabled])])\nelse\n   NE_DISABLE_SUPPORT(LIBPXY, [libproxy support not enabled])\nfi\n])   \n\nAC_DEFUN([NEON_NTLM], [\nAC_ARG_WITH(libntlm, AS_HELP_STRING(--without-libntlm, disable Libntlm support),\n            [need_ntlm=$withval], [need_ntlm=no])\nif test \"$with_libntlm\" != \"no\"; then\n  ne_save_CFLAGS=$CFLAGS\n  ne_save_LIBS=$NEON_LIBS\n  NE_PKG_CONFIG(NE_NTLM, [libntlm],\n    [NE_ENABLE_SUPPORT(NTLM, [NTLM support enabled using Libntlm $NE_NTLM_VERSION])\n     NEON_LIBS=\"$NEON_LIBS ${NE_NTLM_LIBS}\"\n     CPPFLAGS=\"$CPPFLAGS $NE_NTLM_CFLAGS\"\n    ],\n    [NE_DISABLE_SUPPORT(NTLM, [NTLM authentication is not supported])])\nelse\n    NE_DISABLE_SUPPORT(NTLM, [NTLM authentication is not supported])\nfi\n])\n\n\ndnl Adds an --enable-warnings argument to configure to allow enabling\ndnl compiler warnings\nAC_DEFUN([NEON_WARNINGS],[\n\nAC_REQUIRE([AC_PROG_CC]) dnl so that $GCC is set\n\nAC_ARG_ENABLE(warnings,\nAS_HELP_STRING(--enable-warnings, [enable compiler warnings]))\n\nif test \"$enable_warnings\" = \"error\"; then\n   CFLAGS=\"$CFLAGS -Werror\"\n   enable_warnings=yes\nfi\n\nif test \"$enable_warnings\" = \"yes\"; then\n   case $GCC:`uname` in\n   yes:*)\n      CFLAGS=\"$CFLAGS -Wall -Wstrict-prototypes -Wmissing-declarations -Wshadow -Wreturn-type -Wsign-compare -Wundef -Wpointer-arith -Wbad-function-cast -Wformat-security\"\n      if test \"${with_ssl}X${ne_cv_pkg_pakchois}\" = \"opensslXyes\"; then\n         CFLAGS=\"-DOPENSSL_SUPPRESS_DEPRECATED $CFLAGS\"\n      fi\n      if test \"$neon_xml_parser\" = \"libxml2\"; then\n         CFLAGS=\"$CFLAGS -Wno-pointer-sign -Wno-discarded-qualifiers\"\n      fi\n      ;;\n   no:OSF1) CFLAGS=\"$CFLAGS -check -msg_disable returnchecks -msg_disable alignment -msg_disable overflow\" ;;\n   no:IRIX) CFLAGS=\"$CFLAGS -fullwarn\" ;;\n   no:UnixWare) CFLAGS=\"$CFLAGS -v\" ;;\n   *) AC_MSG_WARN([warning flags unknown for compiler on this platform]) ;;\n   esac\nfi\n])\n\ndnl Adds an --disable-debug argument to configure to allow disabling\ndnl debugging messages.\ndnl Usage:\ndnl  NEON_WARNINGS([actions-if-debug-enabled], [actions-if-debug-disabled])\ndnl\nAC_DEFUN([NEON_DEBUG], [\n\nAC_ARG_ENABLE(debug,\nAS_HELP_STRING(--disable-debug,[disable runtime debugging messages]))\n\n# default is to enable debugging\ncase $enable_debug in\nno) AC_MSG_NOTICE([debugging is disabled])\n$2 ;;\n*) AC_MSG_NOTICE([debugging is enabled])\nAC_DEFINE(NE_DEBUGGING, 1, [Define to enable debugging])\n$1\n;;\nesac])\n\ndnl Macro to optionally enable socks support\nAC_DEFUN([NEON_SOCKS], [\n])\n\nAC_DEFUN([NEON_WITH_LIBS], [\nAC_ARG_WITH([libs],\n[[  --with-libs=DIR[:DIR2...] look for support libraries in DIR/{bin,lib,include}]],\n[case $with_libs in\nyes|no) AC_MSG_ERROR([--with-libs must be passed a directory argument]) ;;\n*) ne_save_IFS=$IFS; IFS=:\n   for dir in $with_libs; do\n     ne_add_CPPFLAGS=\"$ne_add_CPPFLAGS -I${dir}/include\"\n     ne_add_LDFLAGS=\"$ne_add_LDFLAGS -L${dir}/lib\"\n     ne_add_PATH=\"${ne_add_PATH}${dir}/bin:\"\n     PKG_CONFIG_PATH=${PKG_CONFIG_PATH}${PKG_CONFIG_PATH+:}${dir}/lib/pkgconfig\n   done\n   IFS=$ne_save_IFS\n   CPPFLAGS=\"${ne_add_CPPFLAGS} $CPPFLAGS\"\n   LDFLAGS=\"${ne_add_LDFLAGS} $LDFLAGS\"\n   PATH=${ne_add_PATH}$PATH \n   export PKG_CONFIG_PATH ;;\nesac])])\n\nAC_DEFUN([NEON_I18N], [\n\ndnl Check for NLS iff libintl.h was detected.\nAC_ARG_ENABLE(nls, \n  AS_HELP_STRING(--disable-nls, [disable internationalization support]),,\n  [enable_nls=${ac_cv_header_libintl_h}])\n\nif test x${enable_nls} = xyes; then\n  # presume that dgettext() is available if bindtextdomain() is...\n  # checking for dgettext() itself is awkward because gcc has a \n  # builtin of that function, which confuses AC_CHECK_FUNCS et al.\n  NE_SEARCH_LIBS(bindtextdomain, intl, -liconv ,[enable_nls=no])\n  NE_CHECK_FUNCS(bind_textdomain_codeset)\nfi\n\nif test \"$enable_nls\" = \"no\"; then\n  NE_DISABLE_SUPPORT(I18N, [Internationalization support not enabled])\nelse\n  NE_ENABLE_SUPPORT(I18N, [Internationalization support enabled])\n  eval localedir=\"${datadir}/locale\"\n  AC_DEFINE_UNQUOTED([LOCALEDIR], \"$localedir\", \n                     [Define to be location of localedir])\nfi\n\n])\n"
  },
  {
    "path": "macros/socklen-arg-type.m4",
    "content": "dnl This function is (C) 1997,98,99 Stephan Kulow (coolo@kde.org)\ndnl Modifications (C) Joe Orton 1999,2000\n\nAC_DEFUN([SOCKLEN_ARG_TYPE],[\n\ndnl Check for the type of the third argument of getsockname\nAC_MSG_CHECKING(for the third argument of getsockname)  \nAC_CACHE_VAL(ac_cv_ksize_t,\n[AC_TRY_COMPILE([\n#include <sys/types.h>\n#include <sys/socket.h>\n],[\nsocklen_t a=0; \ngetsockname(0,(struct sockaddr*)0, &a);\n],\nac_cv_ksize_t=socklen_t,\nac_cv_ksize_t=)\nif test -z \"$ac_cv_ksize_t\"; then\nac_safe_cflags=\"$CFLAGS\"\nif test \"$GCC\" = \"yes\"; then\n  CFLAGS=\"-Werror $CFLAGS\"\nfi\nAC_TRY_COMPILE([\n#include <sys/types.h>\n#include <sys/socket.h>\n],[\nint a=0; \ngetsockname(0,(struct sockaddr*)0, &a);\n],\nac_cv_ksize_t=int,\nac_cv_ksize_t=size_t)\nCFLAGS=\"$ac_safe_cflags\"\nfi\n])\n\nif test -z \"$ac_cv_ksize_t\"; then\n  ac_cv_ksize_t=int\nfi\n\nAC_MSG_RESULT($ac_cv_ksize_t)\nAC_DEFINE_UNQUOTED(ksize_t, $ac_cv_ksize_t, [Define to be the type of the third argument to getsockname])\n\n])"
  },
  {
    "path": "neon-config.in",
    "content": "#! /bin/sh\n# Originally from libxml, Copyright (C) Daniel Veillard\n# Modifications for neon Copyright (C) 2000-2006 Joe Orton.\n\nprefix=@prefix@\nexec_prefix=@exec_prefix@\nincludedir=@includedir@\nlibdir=@libdir@\n\nusage()\n{\n    cat <<EOF\nUsage: neon-config [OPTION]\n\nKnown values for OPTION are:\n\n  --prefix=DIR\t\tchange neon prefix [default $prefix]\n  --libs\t\tprint library linking information\n  --la-file\t\tprint location of libtool .la file\n  --cflags\t\tprint pre-processor and compiler flags\n  --help\t\tdisplay this help and exit\n  --version\t\toutput version information\n  --support FEATURE     exit with success if feature is supported\n\n Known features: \n    dav [@NE_FLAG_DAV@], ssl [@NE_FLAG_SSL@], zlib [@NE_FLAG_ZLIB@], ipv6 [@NE_FLAG_IPV6@], lfs [@NE_FLAG_LFS@],\n    i18n [@NE_FLAG_I18N@], ts_ssl [@NE_FLAG_TS_SSL@], gssapi [@NE_FLAG_GSSAPI@], libpxy [@NE_FLAG_LIBPXY@]\n\nEOF\n\n    exit $1\n}\n\nsupport()\n{\n    if test \"$1\" = \"yes\"; then\n\texit 0\n    else\n\texit 1\n    fi\n}\n\nif test $# -eq 0; then\n    usage 1\nfi\n\nwhile test $# -gt 0; do\n    case \"$1\" in\n    -*=*) optarg=`echo \"$1\" | sed 's/[-_a-zA-Z0-9]*=//'` ;;\n    *) optarg= ;;\n    esac\n\n    case \"$1\" in\n    --prefix=*)\n\tprefix=$optarg\n\t;;\n\n    --prefix)\n\techo $prefix\n\t;;\n\n    --version)\n\techo neon @NEON_VERSION@\n\texit 0\n\t;;\n\n    --help)\n\tusage 0\n\t;;\n\n    --cflags)\n       \techo -I${includedir}/neon @NEON_CFLAGS@\n       \t;;\n\n    --libs)\n        LIBS=\"-lneon @NEON_LIBS@\"\n\t# Don't add standard library paths\n        if test \"$prefix\" != \"/usr\"; then\n           LIBS=\"-L${libdir} ${LIBS}\"\n        fi\n\techo @user_LDFLAGS@ ${LIBS}\n\t;;\n\n    --la-file)\n\techo ${libdir}/libneon.la\n\t;;\n\n    --support)\n\tshift\n\n\tcase \"$1\" in\n\tgssapi|GSSAPI) support @NE_FLAG_GSSAPI@ ;;\n\tlibpxy|LIBPXY) support @NE_FLAG_LIBPXY@ ;;\n\tssl|SSL) support @NE_FLAG_SSL@ ;;\n\tzlib|ZLIB) support @NE_FLAG_ZLIB@ ;;\n\tipv6|IPV6) support @NE_FLAG_IPV6@ ;;\n\tdav|DAV) support @NE_FLAG_DAV@ ;;\n\tlfs|LFS) support @NE_FLAG_LFS@ ;;\n\ti18n|I18N) support @NE_FLAG_I18N@ ;;\n\tts_ssl|TS_SSL) support @NE_FLAG_TS_SSL@ ;;\n\tntlm|NTLM) support @NE_FLAG_NTLM@ ;;\n\t*) support no ;;\n\tesac\n\t;;\n\n    *)\n\tusage 1 1>&2\n\t;;\n    esac\n    shift\ndone\n\nexit 0\n"
  },
  {
    "path": "neon.mak",
    "content": "#**** neon Win32 -*- Makefile -*- ********************************************\n#\n# Define DEBUG_BUILD to create a debug version of the library.\n\n!IF \"$(OS)\" == \"Windows_NT\"\nNULL=\n!ELSE\nNULL=nul\n!ENDIF\n\n!IF \"$(BUILD_DLL)\" == \"yes\"\nUSE_DLL = 1\n!endif\n\n########\n# Debug vs. Release build\n!IF \"$(DEBUG_BUILD)\" == \"\"\nINTDIR = Release\nCFLAGS = /MD /W3 /EHsc /Zi /O2 /D \"NDEBUG\"\nTARGET = .\\libneon.lib\n!ELSE\nINTDIR = Debug\nCFLAGS = /MDd /W3 /Gm /EHsc /Zi /Od /D \"_DEBUG\"\nTARGET = .\\libneonD.lib\n!ENDIF\n\nNE_DEP_LIBS =\n\n!IFDEF USE_DLL\nCFLAGS = $(CFLAGS) /D NE_DLL\nNE_DEP_LIBS = $(NE_DEP_LIBS) ws2_32.lib\n!ENDIF\n\n# Silence deprecation warnings on later Visual Studio versions, which\n# actually can be ignored\nCFLAGS = $(CFLAGS) /D _CRT_SECURE_NO_WARNINGS /D _CRT_NONSTDC_NO_WARNINGS /D _WINSOCK_DEPRECATED_NO_WARNINGS\n\n########\n# Whether to build SSPI\n!IF \"$(SSPI_BUILD)\" != \"\"\nCFLAGS = $(CFLAGS) /D HAVE_SSPI\n!ENDIF\n\n########\n# Support for Expat or libxml2 integration\n#\n# If USE_EXPAT or USE_LIBXML are set, then assume compiling against a\n# pre-built binary Expat or libxml2.  Note that if both are set, USE_EXPAT is\n# assumed and USE_LIBXML is ignored.  If neither of USE_EXPAT or USE_LIBXML are\n# set, disable WebDAV support.\n\n!IF DEFINED (USE_EXPAT) && DEFINED (USE_LIBXML)\n!MESSAGE Expat is preferred over LibXML2\n!ENDIF\n\n!IFDEF USE_EXPAT\nBUILD_XML_SUPPORT = 1\nNE_XML_FLAGS = /D HAVE_EXPAT /D NE_HAVE_DAV\nEXPAT_LIBS = libexpat.lib\nNE_DEP_LIBS = $(NE_DEP_LIBS) $(EXPAT_LIBS)\n!ENDIF\n\n!IF DEFINED(USE_LIBXML) && !DEFINED(USE_EXPAT)\nBUILD_XML_SUPPORT = 1\nNE_XML_FLAGS = /D HAVE_LIBXML /D NE_HAVE_DAV\nLIBXML_LIBS = libxml2.lib\nNE_DEP_LIBS = $(NE_DEP_LIBS) $(LIBXML_LIBS)\n!ENDIF\n\n########\n# Support for OpenSSL integration\n!IF \"$(OPENSSL_SRC)\" == \"\"\n!IF DEFINED (USE_OPENSSL11) || DEFINED (USE_OPENSSL)\nOPENSSL_FLAGS = /D NE_HAVE_SSL /D HAVE_OPENSSL\n!IFDEF USE_OPENSSL11\nOPENSSL_FLAGS = $(OPENSSL_FLAGS) /D HAVE_OPENSSL11\n!ENDIF\nBUILD_OPENSSL = 1\n!ELSE\nOPENSSL_FLAGS =\n!ENDIF\n!ELSE\nOPENSSL_FLAGS = /I \"$(OPENSSL_SRC)\\inc32\" /D NE_HAVE_SSL /D HAVE_OPENSSL\nBUILD_OPENSSL = 1\n!ENDIF\n\n########\n# Support for zlib integration\n!IF \"$(DEBUG_BUILD)\" == \"\"\nZLIB_STATICLIB = zlib.lib\nZLIB_SHAREDLIB = zlib1.dll\n!IF \"$(ZLIB_SRC)\" == \"\"\n!IF \"$(ZLIB_IMPLIB)\" == \"\"\nZLIB_IMPLIB    = zlib1.lib\n!ENDIF\n!ELSE\nZLIB_IMPLIB    = zdll.lib\n!ENDIF\nZLIB_LDFLAGS   = /nologo /release\n!ELSE\nZLIB_STATICLIB = zlib_d.lib\nZLIB_SHAREDLIB = zlib1_d.dll\n!IF \"$(ZLIB_SRC)\" == \"\"\n!IF \"$(ZLIB_IMPLIB)\" == \"\"\nZLIB_IMPLIB    = zlib1d.lib\n!ENDIF\n!ELSE\nZLIB_IMPLIB    = zdll_d.lib\n!ENDIF\nZLIB_LDFLAGS   = /nologo /debug\n!ENDIF\n\n!IF \"$(ZLIB_SRC)\" == \"\"\nZLIB_CLEAN =\n!IF \"$(USE_ZLIB)\" == \"\"\nZLIB_FLAGS =\nZLIB_LIBS =\n!ELSE\nZLIB_FLAGS = /D NE_HAVE_ZLIB\n!IFNDEF ZLIB_LIBS\n!IF \"$(ZLIB_DLL)\" == \"\"\nZLIB_LIBS = $(ZLIB_STATICLIB)\n!ELSE\nZLIB_LIBS = $(ZLIB_IMPLIB)\n!ENDIF\n!ENDIF\n!ENDIF\n!ELSE\nZLIB_CLEAN = ZLIB_CLEAN\nZLIB_FLAGS = /I \"$(ZLIB_SRC)\" /D NE_HAVE_ZLIB\n!IF \"$(ZLIB_DLL)\" == \"\"\nZLIB_LIBS = \"$(ZLIB_SRC)\\$(ZLIB_STATICLIB)\"\n!ELSE\nZLIB_FLAGS = $(ZLIB_FLAGS) /D ZLIB_DLL\nZLIB_LIBS = \"$(ZLIB_SRC)\\$(ZLIB_IMPLIB)\"\n!ENDIF\n!ENDIF\n\n########\n# Support for IPv6\n!IF \"$(ENABLE_IPV6)\" == \"yes\"\nIPV6_FLAGS = /D USE_GETADDRINFO\n!ENDIF\n\n\n# Exclude stuff we don't need from the Win32 headers\nWIN32_DEFS = /D WIN32_LEAN_AND_MEAN /D NOUSER /D NOGDI /D NONLS /D NOCRYPT\n\nCPP=cl.exe\nCPP_PROJ = /c /nologo $(CFLAGS) $(WIN32_DEFS) $(NE_XML_FLAGS) $(OPENSSL_FLAGS) $(ZLIB_FLAGS) $(IPV6_FLAGS) /D \"HAVE_CONFIG_H\" /D BUILDING_NEON /Fo\"$(INTDIR)\\\\\" /Fd\"$(INTDIR)\\\\\"\nLINK=link.exe\nLIB32=$(LINK) -lib\nLIB32_FLAGS=/nologo /out:$@\nLINK_DLL_FLAGS=$(LIB32_FLAGS) /DLL /DEBUG /def:src\\neon.def\n\nLIB32_OBJS= \\\n\t\"$(INTDIR)\\ne_alloc.obj\" \\\n\t\"$(INTDIR)\\ne_auth.obj\" \\\n\t\"$(INTDIR)\\ne_basic.obj\" \\\n\t\"$(INTDIR)\\ne_compress.obj\" \\\n\t\"$(INTDIR)\\ne_dates.obj\" \\\n\t\"$(INTDIR)\\ne_i18n.obj\" \\\n\t\"$(INTDIR)\\ne_md5.obj\" \\\n\t\"$(INTDIR)\\ne_pkcs11.obj\" \\\n\t\"$(INTDIR)\\ne_redirect.obj\" \\\n\t\"$(INTDIR)\\ne_request.obj\" \\\n\t\"$(INTDIR)\\ne_session.obj\" \\\n\t\"$(INTDIR)\\ne_socket.obj\" \\\n\t\"$(INTDIR)\\ne_socks.obj\" \\\n\t\"$(INTDIR)\\ne_sspi.obj\" \\\n\t\"$(INTDIR)\\ne_string.obj\" \\\n\t\"$(INTDIR)\\ne_uri.obj\" \\\n\t\"$(INTDIR)\\ne_utils.obj\"\n\n!IF \"$(BUILD_XML_SUPPORT)\" != \"\"\nLIB32_OBJS= \\\n\t$(LIB32_OBJS) \\\n\t\"$(INTDIR)\\ne_207.obj\" \\\n\t\"$(INTDIR)\\ne_xml.obj\" \\\n\t\"$(INTDIR)\\ne_xmlreq.obj\" \\\n\t\"$(INTDIR)\\ne_oldacl.obj\" \\\n\t\"$(INTDIR)\\ne_acl3744.obj\" \\\n\t\"$(INTDIR)\\ne_props.obj\" \\\n\t\"$(INTDIR)\\ne_locks.obj\" \n!ENDIF\n\n!IFDEF BUILD_OPENSSL\nLIB32_OBJS = $(LIB32_OBJS) \"$(INTDIR)\\ne_openssl.obj\"\n!ENDIF\n!IF \"$(OPENSSL_SRC)\" != \"\"\n!IFDEF OPENSSL_STATIC\nLIB32_OBJS = $(LIB32_OBJS) \"$(OPENSSL_SRC)\\out32\\libeay32.lib\" \\\n\t\t\t   \"$(OPENSSL_SRC)\\out32\\ssleay32.lib\"\n!ELSE\nLIB32_OBJS = $(LIB32_OBJS) \"$(OPENSSL_SRC)\\out32dll\\libeay32.lib\" \\\n\t\t\t   \"$(OPENSSL_SRC)\\out32dll\\ssleay32.lib\"\n!ENDIF\n!ELSE\n!IF DEFINED (USE_OPENSSL11) || DEFINED (USE_OPENSSL)\n!IFDEF USE_OPENSSL11\nSSL_LIBS = libssl.lib libcrypto.lib\n!ELSE\nSSL_LIBS = ssleay32.lib libeay32.lib\n!ENDIF\nNE_DEP_LIBS = $(NE_DEP_LIBS) $(SSL_LIBS)\n!ELSE\n# Provide ABI-compatibility stubs for SSL interface\nLIB32_OBJS = $(LIB32_OBJS) \"$(INTDIR)\\ne_stubssl.obj\"\n!ENDIF\n!ENDIF\n!IF \"$(ZLIB_SRC)\" != \"\"\nLIB32_OBJS = $(LIB32_OBJS) $(ZLIB_LIBS)\n!ENDIF\n!IF \"$(USE_ZLIB)\" != \"\"\nNE_DEP_LIBS = $(NE_DEP_LIBS) $(ZLIB_LIBS)\n!ENDIF\n\nALL: \".\\src\\config.h\" \"$(TARGET)\"\n\nCLEAN: $(ZLIB_CLEAN)\n\t-@erase \"$(INTDIR)\\ne_207.obj\"\n\t-@erase \"$(INTDIR)\\ne_alloc.obj\"\n\t-@erase \"$(INTDIR)\\ne_oldacl.obj\"\n\t-@erase \"$(INTDIR)\\ne_acl3744.obj\"\n\t-@erase \"$(INTDIR)\\ne_auth.obj\"\n\t-@erase \"$(INTDIR)\\ne_basic.obj\"\n\t-@erase \"$(INTDIR)\\ne_compress.obj\"\n\t-@erase \"$(INTDIR)\\ne_dates.obj\"\n\t-@erase \"$(INTDIR)\\ne_i18n.obj\"\n\t-@erase \"$(INTDIR)\\ne_locks.obj\"\n\t-@erase \"$(INTDIR)\\ne_md5.obj\"\n\t-@erase \"$(INTDIR)\\ne_props.obj\"\n\t-@erase \"$(INTDIR)\\ne_redirect.obj\"\n\t-@erase \"$(INTDIR)\\ne_request.obj\"\n\t-@erase \"$(INTDIR)\\ne_session.obj\"\n\t-@erase \"$(INTDIR)\\ne_openssl.obj\"\n\t-@erase \"$(INTDIR)\\ne_stubssl.obj\"\n\t-@erase \"$(INTDIR)\\ne_pkcs11.obj\"\n\t-@erase \"$(INTDIR)\\ne_socket.obj\"\n\t-@erase \"$(INTDIR)\\ne_socks.obj\"\n\t-@erase \"$(INTDIR)\\ne_sspi.obj\"\n\t-@erase \"$(INTDIR)\\ne_string.obj\"\n\t-@erase \"$(INTDIR)\\ne_uri.obj\"\n\t-@erase \"$(INTDIR)\\ne_utils.obj\"\n\t-@erase \"$(INTDIR)\\ne_xml.obj\"\n\t-@erase \"$(INTDIR)\\ne_xmlreq.obj\"\n\t-@erase \"$(TARGET:.lib=.dll)\"\n\t-@erase \"$(TARGET:.lib=.pdb)\"\n\t-@erase \"$(TARGET:.lib=.exp)\"\n\t-@erase \"$(TARGET:.lib=.ilk)\"\n\t-@erase \"$(TARGET)\"\n\t-@erase \".\\src\\config.h\"\n\n!IFDEF USE_DLL\n\"$(TARGET)\": \"$(TARGET:.lib=.dll)\"\n\n\"$(TARGET:.lib=.dll)\": $(LIB32_OBJS)\n\t-@if not exist \"$(INTDIR)/$(NULL)\" mkdir \"$(INTDIR)\"\n\t$(LINK) @<<\n$(LINK_DLL_FLAGS) $(LIB32_OBJS)\t$(NE_DEP_LIBS)\n<<\n\n!ELSE\n\"$(TARGET)\": $(DEF_FILE) $(LIB32_OBJS)\n\t-@if not exist \"$(INTDIR)/$(NULL)\" mkdir \"$(INTDIR)\"\n\t$(LIB32) @<<\n  $(LIB32_FLAGS) $(DEF_FLAGS) $(LIB32_OBJS) $(NE_DEP_LIBS)\n<<\n!ENDIF\n\n{src}.c{$(INTDIR)}.obj::\n\t-@if not exist \"$(INTDIR)/$(NULL)\" mkdir \"$(INTDIR)\"\n\t$(CPP) @<<\n  $(CPP_PROJ) $<\n<<\n\n\".\\src\\config.h\": config.hw\n\t-@if not exist \"$(INTDIR)/$(NULL)\" mkdir \"$(INTDIR)\"\n\t<<tempfile.bat\n  @echo off\n  copy .\\config.hw .\\src\\config.h > nul\n  echo Created config.h from config.hw\n<<\n\n\"$(INTDIR)\\ne_207.obj\":      .\\src\\ne_207.c\n\"$(INTDIR)\\ne_alloc.obj\":    .\\src\\ne_alloc.c\n\"$(INTDIR)\\ne_acl3744.obj\":  .\\src\\ne_acl3744.c\n\"$(INTDIR)\\ne_oldacl.obj\":   .\\src\\ne_oldacl.c\n\"$(INTDIR)\\ne_auth.obj\":     .\\src\\ne_auth.c\n\"$(INTDIR)\\ne_basic.obj\":    .\\src\\ne_basic.c\n\"$(INTDIR)\\ne_compress.obj\": .\\src\\ne_compress.c\n\"$(INTDIR)\\ne_dates.obj\":    .\\src\\ne_dates.c\n\"$(INTDIR)\\ne_i18n.obj\":     .\\src\\ne_i18n.c\n\"$(INTDIR)\\ne_locks.obj\":    .\\src\\ne_locks.c\n\"$(INTDIR)\\ne_md5.obj\":      .\\src\\ne_md5.c\n\"$(INTDIR)\\ne_props.obj\":    .\\src\\ne_props.c\n\"$(INTDIR)\\ne_redirect.obj\": .\\src\\ne_redirect.c\n\"$(INTDIR)\\ne_request.obj\":  .\\src\\ne_request.c\n\"$(INTDIR)\\ne_session.obj\":  .\\src\\ne_session.c\n\"$(INTDIR)\\ne_openssl.obj\":  .\\src\\ne_openssl.c\n\"$(INTDIR)\\ne_stubssl.obj\":  .\\src\\ne_stubssl.c\n\"$(INTDIR)\\ne_pkcs11.obj\":   .\\src\\ne_pkcs11.c\n\"$(INTDIR)\\ne_socket.obj\":   .\\src\\ne_socket.c\n\"$(INTDIR)\\ne_socks.obj\":    .\\src\\ne_socks.c\n\"$(INTDIR)\\ne_sspi.obj\":     .\\src\\ne_sspi.c\n\"$(INTDIR)\\ne_string.obj\":   .\\src\\ne_string.c\n\"$(INTDIR)\\ne_uri.obj\":      .\\src\\ne_uri.c\n\"$(INTDIR)\\ne_utils.obj\":    .\\src\\ne_utils.c\n\"$(INTDIR)\\ne_xml.obj\":      .\\src\\ne_xml.c\n\"$(INTDIR)\\ne_xmlreq.obj\":   .\\src\\ne_xmlreq.c\n\n\"$(ZLIB_SRC)\\$(ZLIB_STATICLIB)\":\n\t<<tempfile.bat\n  @echo off\n  cd /d \"$(ZLIB_SRC)\"\n  $(MAKE) /nologo /f win32\\Makefile.msc CFLAGS=\"/nologo $(CFLAGS)\" LDFLAGS=\"$(ZLIB_LDFLAGS)\" STATICLIB=$(ZLIB_STATICLIB) $(ZLIB_STATICLIB)\n<<\n\n\"$(ZLIB_SRC)\\$(ZLIB_IMPLIB)\":\n\t<<tempfile.bat\n  @echo off\n  cd /d \"$(ZLIB_SRC)\"\n  $(MAKE) /nologo /f win32\\Makefile.msc CFLAGS=\"/nologo $(CFLAGS)\" LDFLAGS=\"$(ZLIB_LDFLAGS)\" SHAREDLIB=$(ZLIB_SHAREDLIB) IMPLIB=$(ZLIB_IMPLIB) $(ZLIB_SHAREDLIB) $(ZLIB_IMPLIB)\n<<\n\nZLIB_CLEAN:\n\t<<tempfile.bat\n  @echo off\n  cd /d \"$(ZLIB_SRC)\"\n  $(MAKE) /nologo /f win32\\Makefile.msc STATICLIB=$(ZLIB_STATICLIB) SHAREDLIB=$(ZLIB_SHAREDLIB) IMPLIB=$(ZLIB_IMPLIB) clean\n<<\n"
  },
  {
    "path": "neon.pc.in",
    "content": "prefix=@prefix@\nexec_prefix=@exec_prefix@\nlibdir=@libdir@\nincludedir=@includedir@\n\nName: neon\nDescription: HTTP/WebDAV client library\nVersion: @NEON_VERSION@\nLibs: -L${libdir} -lneon @NEON_PC_LIBS@\nLibs.private: @NEON_LIBS@\nCflags: -I${includedir}/neon @NEON_CFLAGS@\n"
  },
  {
    "path": "po/cs.po",
    "content": "# The czech translation for sitecopy\n# Copyright (C) 2000 Free Software Foundation, Inc.\n# Petr Prazak <prazak@grisoft.cz>, 2000-2002.\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: sitecopy 0.11.4\\n\"\n\"Report-Msgid-Bugs-To: https://github.com/notroj/neon\\n\"\n\"POT-Creation-Date: 2026-03-15 08:52+0000\\n\"\n\"PO-Revision-Date: 2002-04-09 11:12+0100\\n\"\n\"Last-Translator: Petr Prazak <prazak@grisoft.cz>\\n\"\n\"Language-Team: cz\\n\"\n\"Language: \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=iso-8859-2\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: src/ne_207.c:231\n#, c-format\nmsgid \"\"\n\"Invalid HTTP status line in status element at line %d of response:\\n\"\n\"Status line was: %s\"\nmsgstr \"\"\n\"Neplatn dka HTTP stavu ve stavovm prvku na dku %d odpovdi:\\n\"\n\"Stavov dka byla: %s\"\n\n# src/console_fe.c:961\n#: src/ne_auth.c:130\n#, fuzzy, c-format\nmsgid \"Could not authenticate to server: %s\"\nmsgstr \"Nelze se pipojit k serveru\"\n\n# src/console_fe.c:961\n#: src/ne_auth.c:135\n#, fuzzy, c-format\nmsgid \"Could not authenticate to proxy server: %s\"\nmsgstr \"Nelze se pipojit k proxy serveru\"\n\n#: src/ne_auth.c:338\n#, c-format\nmsgid \"rejected %s challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:379\nmsgid \"missing realm in Basic challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:393\nmsgid \"cannot handle Basic challenge for username containing colon\"\nmsgstr \"\"\n\n#: src/ne_auth.c:496\nmsgid \"invalid Negotiate token\"\nmsgstr \"\"\n\n#: src/ne_auth.c:519\n#, fuzzy\nmsgid \"GSSAPI authentication error: \"\nmsgstr \"Je vyadovna autentizace na %s `%s':\\n\"\n\n#: src/ne_auth.c:532\n#, c-format\nmsgid \"GSSAPI failure (code %u)\"\nmsgstr \"\"\n\n#: src/ne_auth.c:567\nmsgid \"ignoring empty Negotiate continuation\"\nmsgstr \"\"\n\n#: src/ne_auth.c:582\n#, c-format\nmsgid \"Negotiate response verification failed: invalid response header token\"\nmsgstr \"\"\n\n#: src/ne_auth.c:604\n#, c-format\nmsgid \"Negotiate response verification failure: %s\"\nmsgstr \"\"\n\n#: src/ne_auth.c:668\n#, c-format\nmsgid \"SSPI response verification failed: invalid response header token\"\nmsgstr \"\"\n\n#: src/ne_auth.c:794\nmsgid \"unexpected token in NTLM challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:822\nmsgid \"malformed NTLM challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:840\n#, fuzzy\nmsgid \"could not handle NTLM challenge\"\nmsgstr \"Nelze zpracovat velikost bloku\"\n\n#: src/ne_auth.c:908\n#, fuzzy\nmsgid \"could not handle non-ASCII username in Digest challenge\"\nmsgstr \"Nelze zpracovat velikost bloku\"\n\n#: src/ne_auth.c:936\nmsgid \"unknown algorithm in Digest challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:943\nmsgid \"legacy Digest challenge not supported\"\nmsgstr \"\"\n\n#: src/ne_auth.c:947\nmsgid \"incompatible algorithm in Digest challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:951\nmsgid \"missing parameter in Digest challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:955\nmsgid \"initial Digest challenge was stale\"\nmsgstr \"\"\n\n#: src/ne_auth.c:962\nmsgid \"stale Digest challenge with new algorithm or realm\"\nmsgstr \"\"\n\n#: src/ne_auth.c:969\n#, c-format\nmsgid \"%s algorithm in Digest challenge not supported\"\nmsgstr \"\"\n\n#: src/ne_auth.c:985\n#, fuzzy\nmsgid \"could not parse domain in Digest challenge\"\nmsgstr \"Nelze zpracovat velikost bloku\"\n\n#: src/ne_auth.c:992\n#, fuzzy\nmsgid \"cannot create client nonce for Digest challenge\"\nmsgstr \"Nelze zpracovat velikost bloku\"\n\n#: src/ne_auth.c:1273\n#, c-format\nmsgid \"Digest mutual authentication failure: missing parameters\"\nmsgstr \"\"\n\n#: src/ne_auth.c:1278\n#, c-format\nmsgid \"Digest mutual authentication failure: client nonce mismatch\"\nmsgstr \"\"\n\n#: src/ne_auth.c:1287\n#, c-format\nmsgid \"Digest mutual authentication failure: could not parse nonce count\"\nmsgstr \"\"\n\n#: src/ne_auth.c:1292\n#, c-format\nmsgid \"Digest mutual authentication failure: nonce count mismatch (%u not %u)\"\nmsgstr \"\"\n\n#: src/ne_auth.c:1319\n#, c-format\nmsgid \"Digest mutual authentication failure: request-digest mismatch\"\nmsgstr \"\"\n\n#: src/ne_auth.c:1453\n#, c-format\nmsgid \"ignored %s challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:1550\n#, fuzzy\nmsgid \"could not parse challenge\"\nmsgstr \"Nelze zpracovat velikost bloku\"\n\n# src/console_fe.c:992\n#: src/ne_basic.c:98\n#, fuzzy, c-format\nmsgid \"Could not determine file size: %s\"\nmsgstr \"Nelze zjistit dlku souboru: %s\"\n\n#: src/ne_basic.c:201\n#, c-format\nmsgid \"Response did not include requested range\"\nmsgstr \"\"\n\n#: src/ne_basic.c:236\n#, fuzzy, c-format\nmsgid \"Range is not satisfiable\"\nmsgstr \"Rozsah nen uspokojiv.\"\n\n#: src/ne_basic.c:241\n#, fuzzy, c-format\nmsgid \"Resource does not support ranged GET requests\"\nmsgstr \"Server nedovoluje sten pkazy GET.\"\n\n#: src/ne_compress.c:184\n#, c-format\nmsgid \"%s: %s (code %d)\"\nmsgstr \"\"\n\n# src/console_fe.c:992\n#: src/ne_compress.c:232\n#, fuzzy\nmsgid \"Could not inflate data\"\nmsgstr \"Nelze otevt soubor: \"\n\n# src/console_fe.c:992\n#: src/ne_compress.c:293\n#, fuzzy\nmsgid \"Could not initialize zlib\"\nmsgstr \"Nelze otevt soubor: \"\n\n#: src/ne_gnutls.c:181\n#, c-format\nmsgid \"[unprintable:#%lu]\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:209\nmsgid \"[unprintable]\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:633\n#, c-format\nmsgid \"Failed to import private key: %s\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:920\nmsgid \"signed using insecure algorithm\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:923\n#, c-format\nmsgid \"unrecognized errors (%u)\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:965 src/ne_openssl.c:496\nmsgid \"Server certificate was missing commonName attribute in subject name\"\nmsgstr \"\"\n\n# src/console_fe.c:992\n#: src/ne_gnutls.c:979\n#, fuzzy, c-format\nmsgid \"Could not verify server certificate: %s\"\nmsgstr \"Nelze zapsat do souboru: %s\"\n\n#: src/ne_gnutls.c:998 src/ne_openssl.c:487\n#, c-format\nmsgid \"Certificate verification error: %s\"\nmsgstr \"\"\n\n#: src/ne_locks.c:640\nmsgid \"LOCK response missing Lock-Token header\"\nmsgstr \"\"\n\n#: src/ne_locks.c:815\n#, c-format\nmsgid \"Response missing activelock for %s\"\nmsgstr \"\"\n\n#: src/ne_locks.c:860\n#, c-format\nmsgid \"No activelock for <%s> returned in LOCK refresh response\"\nmsgstr \"\"\n\n#: src/ne_props.c:364 src/ne_props.c:428\n#, fuzzy\nmsgid \"Response exceeds maximum property count\"\nmsgstr \"Odpov pekrocila maximln poet poloek v hlavicce.\"\n\n#: src/ne_request.c:210\n#, fuzzy, c-format\nmsgid \"%s: connection was closed by proxy server\"\nmsgstr \"%s: proxy server ukonil spojen.\"\n\n#: src/ne_request.c:213\n#, fuzzy, c-format\nmsgid \"%s: connection was closed by server\"\nmsgstr \"%s: server ukonil spojen.\"\n\n#: src/ne_request.c:218\n#, fuzzy, c-format\nmsgid \"%s: connection timed out\"\nmsgstr \"%s: spojen vyprelo.\"\n\n# src/console_fe.c:992\n#: src/ne_request.c:321\n#, fuzzy, c-format\nmsgid \"Premature EOF in request body file\"\nmsgstr \"Nelze zapsat do souboru: %s\"\n\n# src/console_fe.c:992\n#: src/ne_request.c:328\n#, fuzzy, c-format\nmsgid \"Failed reading request body file: %s\"\nmsgstr \"Nelze zapsat do souboru: %s\"\n\n#: src/ne_request.c:348\nmsgid \"offset invalid\"\nmsgstr \"\"\n\n# src/console_fe.c:992\n#: src/ne_request.c:353\n#, fuzzy, c-format\nmsgid \"Could not seek to offset %s of request body file: %s\"\nmsgstr \"Nelze zapsat do souboru: %s\"\n\n#: src/ne_request.c:439\nmsgid \"Could not send request body\"\nmsgstr \"Nelze odeslat tlo poadavku\"\n\n#: src/ne_request.c:466\n#, fuzzy\nmsgid \"Could not send chunked request terminator\"\nmsgstr \"Nelze poslat poadavek\"\n\n#: src/ne_request.c:842\n#, fuzzy, c-format\nmsgid \"Could not parse redirect destination URL\"\nmsgstr \"Nelze zpracovat stavov dek odpovdi.\"\n\n#: src/ne_request.c:848\n#, fuzzy, c-format\nmsgid \"Could not parse request target URI\"\nmsgstr \"Nelze zpracovat stavov dek odpovdi.\"\n\n#: src/ne_request.c:1024\nmsgid \"Could not read chunk size\"\nmsgstr \"Nelze nast velikost bloku\"\n\n#: src/ne_request.c:1027\nmsgid \"Invalid chunk-size line\"\nmsgstr \"\"\n\n#: src/ne_request.c:1045\nmsgid \"Could not parse chunk size\"\nmsgstr \"Nelze zpracovat velikost bloku\"\n\n#: src/ne_request.c:1085\nmsgid \"Could not read response body\"\nmsgstr \"Nelze nast tlo odpovdi\"\n\n#: src/ne_request.c:1101\n#, fuzzy\nmsgid \"Could not read chunk delimiter\"\nmsgstr \"Nelze nast velikost bloku\"\n\n#: src/ne_request.c:1104\nmsgid \"Chunk delimiter was invalid\"\nmsgstr \"\"\n\n#: src/ne_request.c:1202\nmsgid \"Could not read status line\"\nmsgstr \"Nelze pest stavov dek\"\n\n#: src/ne_request.c:1224\n#, fuzzy\nmsgid \"Could not parse response status line\"\nmsgstr \"Nelze zpracovat stavov dek odpovdi.\"\n\n#: src/ne_request.c:1227\nmsgid \"Incompatible HTTP version\"\nmsgstr \"\"\n\n#: src/ne_request.c:1266\nmsgid \"Could not send request\"\nmsgstr \"Nelze poslat poadavek\"\n\n#: src/ne_request.c:1308\n#, fuzzy\nmsgid \"Timed out reading interim responses\"\nmsgstr \"Nelze nast tlo odpovdi\"\n\n#: src/ne_request.c:1337 src/ne_request.c:1354 src/ne_request.c:1364\nmsgid \"Error reading response headers\"\nmsgstr \"Chyba pi ten hlaviek odpovdi\"\n\n#: src/ne_request.c:1374\n#, c-format\nmsgid \"Response header too long\"\nmsgstr \"Hlavika odpovdi je pli dlouh\"\n\n#: src/ne_request.c:1507\n#, fuzzy\nmsgid \"Response exceeded maximum number of header fields\"\nmsgstr \"Odpov pekrocila maximln poet poloek v hlavicce.\"\n\n# src/console_fe.c:956\n#: src/ne_request.c:1522\n#, fuzzy, c-format\nmsgid \"Could not resolve hostname `%s': %s\"\nmsgstr \"%s: Chyba: Nelze najt adresu vzdlenho potae (%s).\\n\"\n\n#: src/ne_request.c:1645\nmsgid \"Unknown transfer-coding in response\"\nmsgstr \"\"\n\n#: src/ne_request.c:1660\nmsgid \"Invalid Content-Length in response\"\nmsgstr \"\"\n\n# src/console_fe.c:992\n#: src/ne_request.c:1734\n#, c-format\nmsgid \"Could not write to file: %s\"\nmsgstr \"Nelze zapsat do souboru: %s\"\n\n#: src/ne_request.c:1777\n#, fuzzy, c-format\nmsgid \"Response buffer size too small\"\nmsgstr \"Hlavika odpovdi je pli dlouh\"\n\n#: src/ne_request.c:1845\n#, fuzzy, c-format\nmsgid \"Could not create SSL connection through proxy server: %s\"\nmsgstr \"Nelze navzat SSL spojen pes proxy server.\"\n\n#: src/ne_request.c:1884\n#, fuzzy, c-format\nmsgid \"Could not create socket\"\nmsgstr \"Nelze navzat SSL spojen\"\n\n# src/console_fe.c:961\n#: src/ne_request.c:1920\nmsgid \"Could not connect to server\"\nmsgstr \"Nelze se pipojit k serveru\"\n\n# src/console_fe.c:961\n#: src/ne_request.c:1922\nmsgid \"Could not connect to proxy server\"\nmsgstr \"Nelze se pipojit k proxy serveru\"\n\n#: src/ne_request.c:1965\n#, c-format\nmsgid \"Could not find IPv4 address of hostname %s for SOCKS v4 proxy\"\nmsgstr \"\"\n\n#: src/ne_request.c:2023\n#, fuzzy, c-format\nmsgid \"Could not establish connection from SOCKS proxy (%s:%u): %s\"\nmsgstr \"Nelze navzat SSL spojen pes proxy server.\"\n\n# src/common.c:87\n#: src/ne_session.c:236\n#, fuzzy\nmsgid \"Unknown error.\"\nmsgstr \"Neznm systmov chyba\"\n\n#: src/ne_session.c:615\n#, c-format\nmsgid \"Could not set minimum/maximum SSL/TLS versions\"\nmsgstr \"\"\n\n#: src/ne_session.c:622\n#, c-format\nmsgid \"SSL/TLS not enabled for the session\"\nmsgstr \"\"\n\n#: src/ne_session.c:653 src/ne_session.c:664\nmsgid \"[invalid date]\"\nmsgstr \"\"\n\n#: src/ne_session.c:686 src/ne_socket.c:747\n#, fuzzy, c-format\nmsgid \"SSL error: %s\"\nmsgstr \"%s: Chyba: %s\\n\"\n\n# src/console_fe.c:992\n#: src/ne_session.c:712\n#, fuzzy, c-format\nmsgid \"SSL handshake failed: %s\"\nmsgstr \"Nelze zapsat do souboru: %s\"\n\n# src/console_fe.c:992\n#: src/ne_session.c:719\n#, fuzzy, c-format\nmsgid \"No server certificate: %s\"\nmsgstr \"Nelze zapsat do souboru: %s\"\n\n#: src/ne_socket.c:527 src/ne_socket.c:680 src/ne_socket.c:834\n#, fuzzy\nmsgid \"Connection closed\"\nmsgstr \"Server ukonil spojen.\"\n\n#: src/ne_socket.c:685\nmsgid \"Retry operation\"\nmsgstr \"\"\n\n#: src/ne_socket.c:700 src/ne_socket.c:735 src/ne_socket.c:848\n#, fuzzy\nmsgid \"Secure connection truncated\"\nmsgstr \"Spojen vyprelo.\"\n\n#: src/ne_socket.c:705\n#, fuzzy\nmsgid \"Secure connection reset\"\nmsgstr \"Spojen vyprelo.\"\n\n#: src/ne_socket.c:710 src/ne_socket.c:718\nmsgid \"Handshake rejected - client certificate was requested\"\nmsgstr \"\"\n\n# src/console_fe.c:992\n#: src/ne_socket.c:721\n#, fuzzy\nmsgid \"Handshake failed\"\nmsgstr \"Nelze zapsat do souboru: %s\"\n\n#: src/ne_socket.c:750\n#, c-format\nmsgid \"SSL error code %d/%d/%lu\"\nmsgstr \"\"\n\n#: src/ne_socket.c:839\n#, fuzzy, c-format\nmsgid \"SSL alert received: %s\"\nmsgstr \"%s: Chyba: %s\\n\"\n\n#: src/ne_socket.c:860\nmsgid \"SSL socket read failed\"\nmsgstr \"\"\n\n#: src/ne_socket.c:864\nmsgid \" (client certificate was requested)\"\nmsgstr \"\"\n\n#: src/ne_socket.c:868\n#, fuzzy, c-format\nmsgid \"SSL error%s: %s\"\nmsgstr \"%s: Chyba: %s\\n\"\n\n#: src/ne_socket.c:994\nmsgid \"Line too long\"\nmsgstr \"dek je pli dlouh\"\n\n#: src/ne_socket.c:1155 src/ne_socket.c:1161\nmsgid \"Host not found\"\nmsgstr \"Pota nenalezen\"\n\n#: src/ne_socket.c:1404\n#, fuzzy\nmsgid \"Connection timed out\"\nmsgstr \"%s: spojen vyprelo.\"\n\n#: src/ne_socket.c:1603\nmsgid \"Socket descriptor number exceeds FD_SETSIZE\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1665\nmsgid \"Socket family not supported\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1825\nmsgid \"certificate is not yet valid\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1826\nmsgid \"certificate has expired\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1827\nmsgid \"certificate issued for a different hostname\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1828\nmsgid \"issuer is not trusted\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1829\nmsgid \"bad certificate chain\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1830\nmsgid \"certificate has been revoked\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1835\nmsgid \"Server certificate verification failed: \"\nmsgstr \"\"\n\n#: src/ne_socket.c:1913\n#, c-format\nmsgid \"SSL error: failed to set priority string at '%s'\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1968\nmsgid \"Client certificate verification failed\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1990\nmsgid \"SSL disabled due to lack of entropy\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1996\n#, fuzzy\nmsgid \"Could not create SSL structure\"\nmsgstr \"Nelze navzat SSL spojen\"\n\n#: src/ne_socket.c:2210\nmsgid \"SSL server did not present certificate\"\nmsgstr \"\"\n\n#: src/ne_socket.c:2240\nmsgid \"Missing flags for socket shutdown\"\nmsgstr \"\"\n\n#: src/ne_socket.c:2258 src/ne_socket.c:2269 src/ne_socket.c:2284\nmsgid \"Incomplete TLS closure\"\nmsgstr \"\"\n\n#: src/ne_socks.c:65\nmsgid \"failure\"\nmsgstr \"\"\n\n#: src/ne_socks.c:68\n#, fuzzy\nmsgid \"connection not permitted\"\nmsgstr \"%s: spojen vyprelo.\"\n\n#: src/ne_socks.c:71\nmsgid \"network unreachable\"\nmsgstr \"\"\n\n#: src/ne_socks.c:74\nmsgid \"host unreachable\"\nmsgstr \"\"\n\n#: src/ne_socks.c:77\nmsgid \"TTL expired\"\nmsgstr \"\"\n\n#: src/ne_socks.c:80\nmsgid \"command not supported\"\nmsgstr \"\"\n\n#: src/ne_socks.c:83\nmsgid \"address type not supported\"\nmsgstr \"\"\n\n#: src/ne_socks.c:86\n#, c-format\nmsgid \"%s: unrecognized error (%u)\"\nmsgstr \"\"\n\n#: src/ne_socks.c:128 src/ne_socks.c:328\n#, fuzzy\nmsgid \"Could not send message to proxy\"\nmsgstr \"Nelze odeslat tlo poadavku\"\n\n#: src/ne_socks.c:133\n#, fuzzy\nmsgid \"Could not read initial response from proxy\"\nmsgstr \"Nelze nast tlo odpovdi\"\n\n#: src/ne_socks.c:136\nmsgid \"Invalid version in proxy response\"\nmsgstr \"\"\n\n#: src/ne_socks.c:157\n#, fuzzy\nmsgid \"Could not send login message\"\nmsgstr \"Nelze poslat poadavek\"\n\n#: src/ne_socks.c:162\n#, fuzzy\nmsgid \"Could not read login reply\"\nmsgstr \"Nelze pest stavov dek\"\n\n#: src/ne_socks.c:165\nmsgid \"Invalid version in login reply\"\nmsgstr \"\"\n\n#: src/ne_socks.c:168\n#, fuzzy\nmsgid \"Authentication failed\"\nmsgstr \"Je vyadovna autentizace na %s `%s':\\n\"\n\n#: src/ne_socks.c:172\nmsgid \"No acceptable authentication method\"\nmsgstr \"\"\n\n#: src/ne_socks.c:174\nmsgid \"Unexpected authentication method chosen\"\nmsgstr \"\"\n\n#: src/ne_socks.c:210\n#, fuzzy\nmsgid \"Could not send connect request\"\nmsgstr \"Nelze poslat poadavek\"\n\n# src/console_fe.c:961\n#: src/ne_socks.c:215\n#, fuzzy\nmsgid \"Could not read connect reply\"\nmsgstr \"Nelze se pipojit k serveru\"\n\n#: src/ne_socks.c:218\nmsgid \"Invalid version in connect reply\"\nmsgstr \"\"\n\n# src/console_fe.c:961\n#: src/ne_socks.c:221 src/ne_socks.c:337\n#, fuzzy\nmsgid \"Could not connect\"\nmsgstr \"Nelze se pipojit k serveru\"\n\n#: src/ne_socks.c:235\nmsgid \"Could not read FQDN length in connect reply\"\nmsgstr \"\"\n\n#: src/ne_socks.c:240\nmsgid \"Unknown address type in connect reply\"\nmsgstr \"\"\n\n#: src/ne_socks.c:245\n#, fuzzy\nmsgid \"Could not read address in connect reply\"\nmsgstr \"Nelze nast tlo odpovdi\"\n\n#: src/ne_socks.c:266\nmsgid \"request rejected or failed\"\nmsgstr \"\"\n\n# src/console_fe.c:961\n#: src/ne_socks.c:269\n#, fuzzy\nmsgid \"could not establish connection to identd\"\nmsgstr \"Nelze se pipojit k serveru\"\n\n#: src/ne_socks.c:272\nmsgid \"rejected due to identd user mismatch\"\nmsgstr \"\"\n\n#: src/ne_socks.c:275\n#, c-format\nmsgid \"%s: unrecognized failure (%u)\"\nmsgstr \"\"\n\n#: src/ne_socks.c:333\n#, fuzzy\nmsgid \"Could not read response from proxy\"\nmsgstr \"Nelze nast tlo odpovdi\"\n\n# src/console_fe.c:821\n#: src/ne_xml.c:190\n#, fuzzy, c-format\nmsgid \"XML parse error: %s\"\nmsgstr \"Chyba zpracovn XML na dku %d: %s.\"\n\n# src/console_fe.c:821\n#: src/ne_xml.c:305\n#, fuzzy, c-format\nmsgid \"XML parse error at line %d: invalid element name\"\nmsgstr \"Chyba zpracovn XML na dku %d: %s.\"\n\n# src/common.c:87\n#: src/ne_xml.c:499\n#, fuzzy\nmsgid \"Unknown error\"\nmsgstr \"Neznm systmov chyba\"\n\n#: src/ne_xml.c:625\nmsgid \"Invalid Byte Order Mark\"\nmsgstr \"\"\n\n# src/console_fe.c:821\n#: src/ne_xml.c:714\n#, fuzzy, c-format\nmsgid \"XML parse error at line %d: %s\"\nmsgstr \"Chyba zpracovn XML na dku %d: %s.\"\n\n#: src/ne_xmlreq.c:38\n#, fuzzy, c-format\nmsgid \"Could not parse response: %s\"\nmsgstr \"Nelze nast tlo odpovdi\"\n\n#, fuzzy, c-format\n#~ msgid \"%s hash failed for Digest challenge\"\n#~ msgstr \"Nelze zpracovat velikost bloku\"\n\n#, fuzzy\n#~ msgid \"Could not read interim response headers\"\n#~ msgstr \"Nelze nast tlo odpovdi\"\n\n#, fuzzy\n#~ msgid \"%s: %s\"\n#~ msgstr \"%s: Chyba: %s\\n\"\n"
  },
  {
    "path": "po/de.po",
    "content": "# The German translation for sitecopy.\n# Copyright (C) 2000, Thomas Schultz <tststs@gmx.de>\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: sitecopy 0.11.3\\n\"\n\"Report-Msgid-Bugs-To: https://github.com/notroj/neon\\n\"\n\"POT-Creation-Date: 2026-03-15 08:52+0000\\n\"\n\"PO-Revision-Date: 2002-01-13 13:37+0100\\n\"\n\"Last-Translator: Thomas Schultz <tststs@gmx.de>\\n\"\n\"Language-Team: de\\n\"\n\"Language: \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=iso-8859-1\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: src/ne_207.c:231\n#, c-format\nmsgid \"\"\n\"Invalid HTTP status line in status element at line %d of response:\\n\"\n\"Status line was: %s\"\nmsgstr \"\"\n\"Ungltige HTTP Status-Zeile im Status-Element in Zeile %d der Antwort:\\n\"\n\"Status-Zeile war: %s\"\n\n#: src/ne_auth.c:130\n#, fuzzy, c-format\nmsgid \"Could not authenticate to server: %s\"\nmsgstr \"Verbindungsaufbau zum Server gescheitert.\"\n\n#: src/ne_auth.c:135\n#, fuzzy, c-format\nmsgid \"Could not authenticate to proxy server: %s\"\nmsgstr \"Verbindungsaufbau zum Proxy-Server gescheitert.\"\n\n#: src/ne_auth.c:338\n#, c-format\nmsgid \"rejected %s challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:379\nmsgid \"missing realm in Basic challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:393\nmsgid \"cannot handle Basic challenge for username containing colon\"\nmsgstr \"\"\n\n#: src/ne_auth.c:496\nmsgid \"invalid Negotiate token\"\nmsgstr \"\"\n\n#: src/ne_auth.c:519\n#, fuzzy\nmsgid \"GSSAPI authentication error: \"\nmsgstr \"Anmeldung wird bentigt auf %s `%s':\\n\"\n\n#: src/ne_auth.c:532\n#, c-format\nmsgid \"GSSAPI failure (code %u)\"\nmsgstr \"\"\n\n#: src/ne_auth.c:567\nmsgid \"ignoring empty Negotiate continuation\"\nmsgstr \"\"\n\n#: src/ne_auth.c:582\n#, c-format\nmsgid \"Negotiate response verification failed: invalid response header token\"\nmsgstr \"\"\n\n#: src/ne_auth.c:604\n#, c-format\nmsgid \"Negotiate response verification failure: %s\"\nmsgstr \"\"\n\n#: src/ne_auth.c:668\n#, c-format\nmsgid \"SSPI response verification failed: invalid response header token\"\nmsgstr \"\"\n\n#: src/ne_auth.c:794\nmsgid \"unexpected token in NTLM challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:822\nmsgid \"malformed NTLM challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:840\n#, fuzzy\nmsgid \"could not handle NTLM challenge\"\nmsgstr \"Parser-Fehler bei Ermittlung der Blockgre\"\n\n#: src/ne_auth.c:908\n#, fuzzy\nmsgid \"could not handle non-ASCII username in Digest challenge\"\nmsgstr \"Parser-Fehler bei Ermittlung der Blockgre\"\n\n#: src/ne_auth.c:936\nmsgid \"unknown algorithm in Digest challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:943\nmsgid \"legacy Digest challenge not supported\"\nmsgstr \"\"\n\n#: src/ne_auth.c:947\nmsgid \"incompatible algorithm in Digest challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:951\nmsgid \"missing parameter in Digest challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:955\nmsgid \"initial Digest challenge was stale\"\nmsgstr \"\"\n\n#: src/ne_auth.c:962\nmsgid \"stale Digest challenge with new algorithm or realm\"\nmsgstr \"\"\n\n#: src/ne_auth.c:969\n#, c-format\nmsgid \"%s algorithm in Digest challenge not supported\"\nmsgstr \"\"\n\n#: src/ne_auth.c:985\n#, fuzzy\nmsgid \"could not parse domain in Digest challenge\"\nmsgstr \"Parser-Fehler bei Ermittlung der Blockgre\"\n\n#: src/ne_auth.c:992\n#, fuzzy\nmsgid \"cannot create client nonce for Digest challenge\"\nmsgstr \"Parser-Fehler bei Ermittlung der Blockgre\"\n\n#: src/ne_auth.c:1273\n#, c-format\nmsgid \"Digest mutual authentication failure: missing parameters\"\nmsgstr \"\"\n\n#: src/ne_auth.c:1278\n#, c-format\nmsgid \"Digest mutual authentication failure: client nonce mismatch\"\nmsgstr \"\"\n\n#: src/ne_auth.c:1287\n#, c-format\nmsgid \"Digest mutual authentication failure: could not parse nonce count\"\nmsgstr \"\"\n\n#: src/ne_auth.c:1292\n#, c-format\nmsgid \"Digest mutual authentication failure: nonce count mismatch (%u not %u)\"\nmsgstr \"\"\n\n#: src/ne_auth.c:1319\n#, c-format\nmsgid \"Digest mutual authentication failure: request-digest mismatch\"\nmsgstr \"\"\n\n#: src/ne_auth.c:1453\n#, c-format\nmsgid \"ignored %s challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:1550\n#, fuzzy\nmsgid \"could not parse challenge\"\nmsgstr \"Parser-Fehler bei Ermittlung der Blockgre\"\n\n#: src/ne_basic.c:98\n#, fuzzy, c-format\nmsgid \"Could not determine file size: %s\"\nmsgstr \"Konnte Lnge der Datei nicht herausfinden: %s\"\n\n#: src/ne_basic.c:201\n#, c-format\nmsgid \"Response did not include requested range\"\nmsgstr \"\"\n\n#: src/ne_basic.c:236\n#, fuzzy, c-format\nmsgid \"Range is not satisfiable\"\nmsgstr \"Range is not satisfiable.\"\n\n#: src/ne_basic.c:241\n#, fuzzy, c-format\nmsgid \"Resource does not support ranged GET requests\"\nmsgstr \"Server ermglicht keine teilweisen GETs.\"\n\n#: src/ne_compress.c:184\n#, c-format\nmsgid \"%s: %s (code %d)\"\nmsgstr \"\"\n\n#: src/ne_compress.c:232\n#, fuzzy\nmsgid \"Could not inflate data\"\nmsgstr \"Konnte Datei nicht ffnen: \"\n\n#: src/ne_compress.c:293\n#, fuzzy\nmsgid \"Could not initialize zlib\"\nmsgstr \"Konnte Datei nicht ffnen: \"\n\n#: src/ne_gnutls.c:181\n#, c-format\nmsgid \"[unprintable:#%lu]\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:209\nmsgid \"[unprintable]\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:633\n#, c-format\nmsgid \"Failed to import private key: %s\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:920\nmsgid \"signed using insecure algorithm\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:923\n#, c-format\nmsgid \"unrecognized errors (%u)\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:965 src/ne_openssl.c:496\nmsgid \"Server certificate was missing commonName attribute in subject name\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:979\n#, fuzzy, c-format\nmsgid \"Could not verify server certificate: %s\"\nmsgstr \"Konnte nicht in diese Datei schreiben: %s\"\n\n#: src/ne_gnutls.c:998 src/ne_openssl.c:487\n#, c-format\nmsgid \"Certificate verification error: %s\"\nmsgstr \"\"\n\n#: src/ne_locks.c:640\nmsgid \"LOCK response missing Lock-Token header\"\nmsgstr \"\"\n\n#: src/ne_locks.c:815\n#, c-format\nmsgid \"Response missing activelock for %s\"\nmsgstr \"\"\n\n#: src/ne_locks.c:860\n#, c-format\nmsgid \"No activelock for <%s> returned in LOCK refresh response\"\nmsgstr \"\"\n\n#: src/ne_props.c:364 src/ne_props.c:428\n#, fuzzy\nmsgid \"Response exceeds maximum property count\"\nmsgstr \"Antwort hatte zu viele Header-Felder.\"\n\n#: src/ne_request.c:210\n#, fuzzy, c-format\nmsgid \"%s: connection was closed by proxy server\"\nmsgstr \"%s: Verbindung vom Proxy-Server geschlossen.\"\n\n#: src/ne_request.c:213\n#, fuzzy, c-format\nmsgid \"%s: connection was closed by server\"\nmsgstr \"%s: Verbindung vom Server geschlossen.\"\n\n#: src/ne_request.c:218\n#, fuzzy, c-format\nmsgid \"%s: connection timed out\"\nmsgstr \"%s: Verbindung wegen Zeitberschreitung geschlossen.\"\n\n#: src/ne_request.c:321\n#, fuzzy, c-format\nmsgid \"Premature EOF in request body file\"\nmsgstr \"Konnte nicht in diese Datei schreiben: %s\"\n\n#: src/ne_request.c:328\n#, fuzzy, c-format\nmsgid \"Failed reading request body file: %s\"\nmsgstr \"Konnte nicht in diese Datei schreiben: %s\"\n\n#: src/ne_request.c:348\nmsgid \"offset invalid\"\nmsgstr \"\"\n\n#: src/ne_request.c:353\n#, fuzzy, c-format\nmsgid \"Could not seek to offset %s of request body file: %s\"\nmsgstr \"Konnte nicht in diese Datei schreiben: %s\"\n\n#: src/ne_request.c:439\nmsgid \"Could not send request body\"\nmsgstr \"Konnte den Rumpf der Anfrage nicht schicken\"\n\n#: src/ne_request.c:466\n#, fuzzy\nmsgid \"Could not send chunked request terminator\"\nmsgstr \"Konnte keine Anfrage (request) schicken\"\n\n#: src/ne_request.c:842\n#, fuzzy, c-format\nmsgid \"Could not parse redirect destination URL\"\nmsgstr \"Konnte Status-Zeile des Servers nicht interpretieren.\"\n\n#: src/ne_request.c:848\n#, fuzzy, c-format\nmsgid \"Could not parse request target URI\"\nmsgstr \"Konnte Status-Zeile des Servers nicht interpretieren.\"\n\n#: src/ne_request.c:1024\nmsgid \"Could not read chunk size\"\nmsgstr \"Lesefehler bei Ermittlung der Blockgre\"\n\n#: src/ne_request.c:1027\nmsgid \"Invalid chunk-size line\"\nmsgstr \"\"\n\n#: src/ne_request.c:1045\nmsgid \"Could not parse chunk size\"\nmsgstr \"Parser-Fehler bei Ermittlung der Blockgre\"\n\n#: src/ne_request.c:1085\nmsgid \"Could not read response body\"\nmsgstr \"Konnte Rumpf der Antwort nicht lesen\"\n\n#: src/ne_request.c:1101\n#, fuzzy\nmsgid \"Could not read chunk delimiter\"\nmsgstr \"Lesefehler bei Ermittlung der Blockgre\"\n\n#: src/ne_request.c:1104\nmsgid \"Chunk delimiter was invalid\"\nmsgstr \"\"\n\n#: src/ne_request.c:1202\nmsgid \"Could not read status line\"\nmsgstr \"Konnte Status-Zeile des Servers nicht lesen\"\n\n#: src/ne_request.c:1224\n#, fuzzy\nmsgid \"Could not parse response status line\"\nmsgstr \"Konnte Status-Zeile des Servers nicht interpretieren.\"\n\n#: src/ne_request.c:1227\nmsgid \"Incompatible HTTP version\"\nmsgstr \"\"\n\n#: src/ne_request.c:1266\nmsgid \"Could not send request\"\nmsgstr \"Konnte keine Anfrage (request) schicken\"\n\n#: src/ne_request.c:1308\n#, fuzzy\nmsgid \"Timed out reading interim responses\"\nmsgstr \"Konnte Rumpf der Antwort nicht lesen\"\n\n#: src/ne_request.c:1337 src/ne_request.c:1354 src/ne_request.c:1364\nmsgid \"Error reading response headers\"\nmsgstr \"Fehler beim Lesen der Kopfzeilen (header) der Antwort\"\n\n#: src/ne_request.c:1374\n#, c-format\nmsgid \"Response header too long\"\nmsgstr \"Kopfzeilen (header) der Antwort zu lang\"\n\n#: src/ne_request.c:1507\n#, fuzzy\nmsgid \"Response exceeded maximum number of header fields\"\nmsgstr \"Antwort hatte zu viele Header-Felder.\"\n\n#: src/ne_request.c:1522\n#, fuzzy, c-format\nmsgid \"Could not resolve hostname `%s': %s\"\nmsgstr \"%s: Fehler: Konnte den Namen des Servers nicht auflsen (%s).\\n\"\n\n#: src/ne_request.c:1645\nmsgid \"Unknown transfer-coding in response\"\nmsgstr \"\"\n\n#: src/ne_request.c:1660\nmsgid \"Invalid Content-Length in response\"\nmsgstr \"\"\n\n#: src/ne_request.c:1734\n#, c-format\nmsgid \"Could not write to file: %s\"\nmsgstr \"Konnte nicht in diese Datei schreiben: %s\"\n\n#: src/ne_request.c:1777\n#, fuzzy, c-format\nmsgid \"Response buffer size too small\"\nmsgstr \"Kopfzeilen (header) der Antwort zu lang\"\n\n#: src/ne_request.c:1845\n#, fuzzy, c-format\nmsgid \"Could not create SSL connection through proxy server: %s\"\nmsgstr \"Konnte durch den Proxy-Server keine SSL-Verbindung herstellen\"\n\n#: src/ne_request.c:1884\n#, fuzzy, c-format\nmsgid \"Could not create socket\"\nmsgstr \"Konnte keine SSL-Sitzung herstellen\"\n\n#: src/ne_request.c:1920\nmsgid \"Could not connect to server\"\nmsgstr \"Verbindungsaufbau zum Server gescheitert.\"\n\n#: src/ne_request.c:1922\nmsgid \"Could not connect to proxy server\"\nmsgstr \"Verbindungsaufbau zum Proxy-Server gescheitert.\"\n\n#: src/ne_request.c:1965\n#, c-format\nmsgid \"Could not find IPv4 address of hostname %s for SOCKS v4 proxy\"\nmsgstr \"\"\n\n#: src/ne_request.c:2023\n#, fuzzy, c-format\nmsgid \"Could not establish connection from SOCKS proxy (%s:%u): %s\"\nmsgstr \"Konnte durch den Proxy-Server keine SSL-Verbindung herstellen\"\n\n#: src/ne_session.c:236\n#, fuzzy\nmsgid \"Unknown error.\"\nmsgstr \"Unbekannter System-Fehler\"\n\n#: src/ne_session.c:615\n#, c-format\nmsgid \"Could not set minimum/maximum SSL/TLS versions\"\nmsgstr \"\"\n\n#: src/ne_session.c:622\n#, c-format\nmsgid \"SSL/TLS not enabled for the session\"\nmsgstr \"\"\n\n#: src/ne_session.c:653 src/ne_session.c:664\nmsgid \"[invalid date]\"\nmsgstr \"\"\n\n#: src/ne_session.c:686 src/ne_socket.c:747\n#, fuzzy, c-format\nmsgid \"SSL error: %s\"\nmsgstr \"%s: Fehler: %s\\n\"\n\n#: src/ne_session.c:712\n#, fuzzy, c-format\nmsgid \"SSL handshake failed: %s\"\nmsgstr \"Konnte nicht in diese Datei schreiben: %s\"\n\n#: src/ne_session.c:719\n#, fuzzy, c-format\nmsgid \"No server certificate: %s\"\nmsgstr \"Konnte nicht in diese Datei schreiben: %s\"\n\n#: src/ne_socket.c:527 src/ne_socket.c:680 src/ne_socket.c:834\n#, fuzzy\nmsgid \"Connection closed\"\nmsgstr \"Verbindung vom Server geschlossen\"\n\n#: src/ne_socket.c:685\nmsgid \"Retry operation\"\nmsgstr \"\"\n\n#: src/ne_socket.c:700 src/ne_socket.c:735 src/ne_socket.c:848\n#, fuzzy\nmsgid \"Secure connection truncated\"\nmsgstr \"Verbindung wegen Zeitberschreitung abgebrochen.\"\n\n#: src/ne_socket.c:705\n#, fuzzy\nmsgid \"Secure connection reset\"\nmsgstr \"Verbindung wegen Zeitberschreitung abgebrochen.\"\n\n#: src/ne_socket.c:710 src/ne_socket.c:718\nmsgid \"Handshake rejected - client certificate was requested\"\nmsgstr \"\"\n\n#: src/ne_socket.c:721\n#, fuzzy\nmsgid \"Handshake failed\"\nmsgstr \"Konnte nicht in diese Datei schreiben: %s\"\n\n#: src/ne_socket.c:750\n#, c-format\nmsgid \"SSL error code %d/%d/%lu\"\nmsgstr \"\"\n\n#: src/ne_socket.c:839\n#, fuzzy, c-format\nmsgid \"SSL alert received: %s\"\nmsgstr \"%s: Fehler: %s\\n\"\n\n#: src/ne_socket.c:860\nmsgid \"SSL socket read failed\"\nmsgstr \"\"\n\n#: src/ne_socket.c:864\nmsgid \" (client certificate was requested)\"\nmsgstr \"\"\n\n#: src/ne_socket.c:868\n#, fuzzy, c-format\nmsgid \"SSL error%s: %s\"\nmsgstr \"%s: Fehler: %s\\n\"\n\n#: src/ne_socket.c:994\nmsgid \"Line too long\"\nmsgstr \"Zeile zu lang\"\n\n#: src/ne_socket.c:1155 src/ne_socket.c:1161\nmsgid \"Host not found\"\nmsgstr \"Host nicht gefunden\"\n\n#: src/ne_socket.c:1404\n#, fuzzy\nmsgid \"Connection timed out\"\nmsgstr \"%s: Verbindung wegen Zeitberschreitung geschlossen.\"\n\n#: src/ne_socket.c:1603\nmsgid \"Socket descriptor number exceeds FD_SETSIZE\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1665\nmsgid \"Socket family not supported\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1825\nmsgid \"certificate is not yet valid\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1826\nmsgid \"certificate has expired\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1827\nmsgid \"certificate issued for a different hostname\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1828\nmsgid \"issuer is not trusted\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1829\nmsgid \"bad certificate chain\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1830\nmsgid \"certificate has been revoked\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1835\nmsgid \"Server certificate verification failed: \"\nmsgstr \"\"\n\n#: src/ne_socket.c:1913\n#, c-format\nmsgid \"SSL error: failed to set priority string at '%s'\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1968\nmsgid \"Client certificate verification failed\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1990\nmsgid \"SSL disabled due to lack of entropy\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1996\n#, fuzzy\nmsgid \"Could not create SSL structure\"\nmsgstr \"Konnte keine SSL-Sitzung herstellen\"\n\n#: src/ne_socket.c:2210\nmsgid \"SSL server did not present certificate\"\nmsgstr \"\"\n\n#: src/ne_socket.c:2240\nmsgid \"Missing flags for socket shutdown\"\nmsgstr \"\"\n\n#: src/ne_socket.c:2258 src/ne_socket.c:2269 src/ne_socket.c:2284\nmsgid \"Incomplete TLS closure\"\nmsgstr \"\"\n\n#: src/ne_socks.c:65\nmsgid \"failure\"\nmsgstr \"\"\n\n#: src/ne_socks.c:68\n#, fuzzy\nmsgid \"connection not permitted\"\nmsgstr \"%s: Verbindung wegen Zeitberschreitung geschlossen.\"\n\n#: src/ne_socks.c:71\nmsgid \"network unreachable\"\nmsgstr \"\"\n\n#: src/ne_socks.c:74\nmsgid \"host unreachable\"\nmsgstr \"\"\n\n#: src/ne_socks.c:77\nmsgid \"TTL expired\"\nmsgstr \"\"\n\n#: src/ne_socks.c:80\nmsgid \"command not supported\"\nmsgstr \"\"\n\n#: src/ne_socks.c:83\nmsgid \"address type not supported\"\nmsgstr \"\"\n\n#: src/ne_socks.c:86\n#, c-format\nmsgid \"%s: unrecognized error (%u)\"\nmsgstr \"\"\n\n#: src/ne_socks.c:128 src/ne_socks.c:328\n#, fuzzy\nmsgid \"Could not send message to proxy\"\nmsgstr \"Konnte den Rumpf der Anfrage nicht schicken\"\n\n#: src/ne_socks.c:133\n#, fuzzy\nmsgid \"Could not read initial response from proxy\"\nmsgstr \"Konnte Rumpf der Antwort nicht lesen\"\n\n#: src/ne_socks.c:136\nmsgid \"Invalid version in proxy response\"\nmsgstr \"\"\n\n#: src/ne_socks.c:157\n#, fuzzy\nmsgid \"Could not send login message\"\nmsgstr \"Konnte keine Anfrage (request) schicken\"\n\n#: src/ne_socks.c:162\n#, fuzzy\nmsgid \"Could not read login reply\"\nmsgstr \"Konnte Status-Zeile des Servers nicht lesen\"\n\n#: src/ne_socks.c:165\nmsgid \"Invalid version in login reply\"\nmsgstr \"\"\n\n#: src/ne_socks.c:168\n#, fuzzy\nmsgid \"Authentication failed\"\nmsgstr \"Anmeldung wird bentigt auf %s `%s':\\n\"\n\n#: src/ne_socks.c:172\nmsgid \"No acceptable authentication method\"\nmsgstr \"\"\n\n#: src/ne_socks.c:174\nmsgid \"Unexpected authentication method chosen\"\nmsgstr \"\"\n\n#: src/ne_socks.c:210\n#, fuzzy\nmsgid \"Could not send connect request\"\nmsgstr \"Konnte keine Anfrage (request) schicken\"\n\n#: src/ne_socks.c:215\n#, fuzzy\nmsgid \"Could not read connect reply\"\nmsgstr \"Verbindungsaufbau zum Server gescheitert.\"\n\n#: src/ne_socks.c:218\nmsgid \"Invalid version in connect reply\"\nmsgstr \"\"\n\n#: src/ne_socks.c:221 src/ne_socks.c:337\n#, fuzzy\nmsgid \"Could not connect\"\nmsgstr \"Verbindungsaufbau zum Server gescheitert.\"\n\n#: src/ne_socks.c:235\nmsgid \"Could not read FQDN length in connect reply\"\nmsgstr \"\"\n\n#: src/ne_socks.c:240\nmsgid \"Unknown address type in connect reply\"\nmsgstr \"\"\n\n#: src/ne_socks.c:245\n#, fuzzy\nmsgid \"Could not read address in connect reply\"\nmsgstr \"Konnte Rumpf der Antwort nicht lesen\"\n\n#: src/ne_socks.c:266\nmsgid \"request rejected or failed\"\nmsgstr \"\"\n\n#: src/ne_socks.c:269\n#, fuzzy\nmsgid \"could not establish connection to identd\"\nmsgstr \"Verbindungsaufbau zum Server gescheitert.\"\n\n#: src/ne_socks.c:272\nmsgid \"rejected due to identd user mismatch\"\nmsgstr \"\"\n\n#: src/ne_socks.c:275\n#, c-format\nmsgid \"%s: unrecognized failure (%u)\"\nmsgstr \"\"\n\n#: src/ne_socks.c:333\n#, fuzzy\nmsgid \"Could not read response from proxy\"\nmsgstr \"Konnte Rumpf der Antwort nicht lesen\"\n\n#: src/ne_xml.c:190\n#, fuzzy, c-format\nmsgid \"XML parse error: %s\"\nmsgstr \"Fehler beim XML-Parsing in Zeile %d: %s.\"\n\n#: src/ne_xml.c:305\n#, fuzzy, c-format\nmsgid \"XML parse error at line %d: invalid element name\"\nmsgstr \"Fehler beim XML-Parsing in Zeile %d: %s.\"\n\n#: src/ne_xml.c:499\n#, fuzzy\nmsgid \"Unknown error\"\nmsgstr \"Unbekannter System-Fehler\"\n\n#: src/ne_xml.c:625\nmsgid \"Invalid Byte Order Mark\"\nmsgstr \"\"\n\n#: src/ne_xml.c:714\n#, fuzzy, c-format\nmsgid \"XML parse error at line %d: %s\"\nmsgstr \"Fehler beim XML-Parsing in Zeile %d: %s.\"\n\n#: src/ne_xmlreq.c:38\n#, fuzzy, c-format\nmsgid \"Could not parse response: %s\"\nmsgstr \"Konnte Rumpf der Antwort nicht lesen\"\n\n#, fuzzy, c-format\n#~ msgid \"%s hash failed for Digest challenge\"\n#~ msgstr \"Parser-Fehler bei Ermittlung der Blockgre\"\n\n#, fuzzy\n#~ msgid \"Could not read interim response headers\"\n#~ msgstr \"Konnte Rumpf der Antwort nicht lesen\"\n\n#, fuzzy\n#~ msgid \"%s: %s\"\n#~ msgstr \"%s: %s\\n\"\n"
  },
  {
    "path": "po/fr.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2000 Sylvain Glaize <mokona@puupuu.org>\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: sitecopy 0.9.3\\n\"\n\"Report-Msgid-Bugs-To: https://github.com/notroj/neon\\n\"\n\"POT-Creation-Date: 2026-03-15 08:52+0000\\n\"\n\"PO-Revision-Date: 2000-01-31 00:00+0100\\n\"\n\"Last-Translator: Sylvain Glaize <mokona@puupuu.org>\\n\"\n\"Language-Team: fr\\n\"\n\"Language: \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=ISO-8859-1\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: src/ne_207.c:231\n#, c-format\nmsgid \"\"\n\"Invalid HTTP status line in status element at line %d of response:\\n\"\n\"Status line was: %s\"\nmsgstr \"\"\n\n#: src/ne_auth.c:130\n#, fuzzy, c-format\nmsgid \"Could not authenticate to server: %s\"\nmsgstr \"%s: erreur: impossible de se connecter  l'hte distant.\\n\"\n\n#: src/ne_auth.c:135\n#, fuzzy, c-format\nmsgid \"Could not authenticate to proxy server: %s\"\nmsgstr \"%s: erreur: impossible de se connecter  l'hte distant.\\n\"\n\n#: src/ne_auth.c:338\n#, c-format\nmsgid \"rejected %s challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:379\nmsgid \"missing realm in Basic challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:393\nmsgid \"cannot handle Basic challenge for username containing colon\"\nmsgstr \"\"\n\n#: src/ne_auth.c:496\nmsgid \"invalid Negotiate token\"\nmsgstr \"\"\n\n#: src/ne_auth.c:519\nmsgid \"GSSAPI authentication error: \"\nmsgstr \"\"\n\n#: src/ne_auth.c:532\n#, c-format\nmsgid \"GSSAPI failure (code %u)\"\nmsgstr \"\"\n\n#: src/ne_auth.c:567\nmsgid \"ignoring empty Negotiate continuation\"\nmsgstr \"\"\n\n#: src/ne_auth.c:582\n#, c-format\nmsgid \"Negotiate response verification failed: invalid response header token\"\nmsgstr \"\"\n\n#: src/ne_auth.c:604\n#, c-format\nmsgid \"Negotiate response verification failure: %s\"\nmsgstr \"\"\n\n#: src/ne_auth.c:668\n#, c-format\nmsgid \"SSPI response verification failed: invalid response header token\"\nmsgstr \"\"\n\n#: src/ne_auth.c:794\nmsgid \"unexpected token in NTLM challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:822\nmsgid \"malformed NTLM challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:840\n#, fuzzy\nmsgid \"could not handle NTLM challenge\"\nmsgstr \"%s: erreur: impossible d'ouvrir le fichier de ressources: %s\\n\"\n\n#: src/ne_auth.c:908\n#, fuzzy\nmsgid \"could not handle non-ASCII username in Digest challenge\"\nmsgstr \"%s: erreur: impossible d'ouvrir le fichier de ressources: %s\\n\"\n\n#: src/ne_auth.c:936\nmsgid \"unknown algorithm in Digest challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:943\nmsgid \"legacy Digest challenge not supported\"\nmsgstr \"\"\n\n#: src/ne_auth.c:947\nmsgid \"incompatible algorithm in Digest challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:951\nmsgid \"missing parameter in Digest challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:955\nmsgid \"initial Digest challenge was stale\"\nmsgstr \"\"\n\n#: src/ne_auth.c:962\nmsgid \"stale Digest challenge with new algorithm or realm\"\nmsgstr \"\"\n\n#: src/ne_auth.c:969\n#, c-format\nmsgid \"%s algorithm in Digest challenge not supported\"\nmsgstr \"\"\n\n#: src/ne_auth.c:985\n#, fuzzy\nmsgid \"could not parse domain in Digest challenge\"\nmsgstr \"%s: erreur: impossible d'ouvrir le fichier de ressources: %s\\n\"\n\n#: src/ne_auth.c:992\n#, fuzzy\nmsgid \"cannot create client nonce for Digest challenge\"\nmsgstr \"%s: erreur: impossible d'ouvrir le fichier de ressources: %s\\n\"\n\n#: src/ne_auth.c:1273\n#, c-format\nmsgid \"Digest mutual authentication failure: missing parameters\"\nmsgstr \"\"\n\n#: src/ne_auth.c:1278\n#, c-format\nmsgid \"Digest mutual authentication failure: client nonce mismatch\"\nmsgstr \"\"\n\n#: src/ne_auth.c:1287\n#, c-format\nmsgid \"Digest mutual authentication failure: could not parse nonce count\"\nmsgstr \"\"\n\n#: src/ne_auth.c:1292\n#, c-format\nmsgid \"Digest mutual authentication failure: nonce count mismatch (%u not %u)\"\nmsgstr \"\"\n\n#: src/ne_auth.c:1319\n#, c-format\nmsgid \"Digest mutual authentication failure: request-digest mismatch\"\nmsgstr \"\"\n\n#: src/ne_auth.c:1453\n#, c-format\nmsgid \"ignored %s challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:1550\n#, fuzzy\nmsgid \"could not parse challenge\"\nmsgstr \"%s: erreur: impossible d'ouvrir le fichier de ressources: %s\\n\"\n\n#: src/ne_basic.c:98\n#, fuzzy, c-format\nmsgid \"Could not determine file size: %s\"\nmsgstr \"%s: erreur: impossible d'ouvrir le fichier de ressources: %s\\n\"\n\n#: src/ne_basic.c:201\n#, c-format\nmsgid \"Response did not include requested range\"\nmsgstr \"\"\n\n#: src/ne_basic.c:236\n#, c-format\nmsgid \"Range is not satisfiable\"\nmsgstr \"\"\n\n#: src/ne_basic.c:241\n#, c-format\nmsgid \"Resource does not support ranged GET requests\"\nmsgstr \"\"\n\n#: src/ne_compress.c:184\n#, c-format\nmsgid \"%s: %s (code %d)\"\nmsgstr \"\"\n\n#: src/ne_compress.c:232\n#, fuzzy\nmsgid \"Could not inflate data\"\nmsgstr \"%s: erreur: impossible d'ouvrir le fichier de ressources: %s\\n\"\n\n#: src/ne_compress.c:293\n#, fuzzy\nmsgid \"Could not initialize zlib\"\nmsgstr \"%s: erreur: impossible d'ouvrir le fichier de ressources: %s\\n\"\n\n#: src/ne_gnutls.c:181\n#, c-format\nmsgid \"[unprintable:#%lu]\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:209\nmsgid \"[unprintable]\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:633\n#, c-format\nmsgid \"Failed to import private key: %s\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:920\nmsgid \"signed using insecure algorithm\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:923\n#, c-format\nmsgid \"unrecognized errors (%u)\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:965 src/ne_openssl.c:496\nmsgid \"Server certificate was missing commonName attribute in subject name\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:979\n#, fuzzy, c-format\nmsgid \"Could not verify server certificate: %s\"\nmsgstr \"%s: erreur: impossible d'ouvrir le fichier de ressources: %s\\n\"\n\n#: src/ne_gnutls.c:998 src/ne_openssl.c:487\n#, c-format\nmsgid \"Certificate verification error: %s\"\nmsgstr \"\"\n\n#: src/ne_locks.c:640\nmsgid \"LOCK response missing Lock-Token header\"\nmsgstr \"\"\n\n#: src/ne_locks.c:815\n#, c-format\nmsgid \"Response missing activelock for %s\"\nmsgstr \"\"\n\n#: src/ne_locks.c:860\n#, c-format\nmsgid \"No activelock for <%s> returned in LOCK refresh response\"\nmsgstr \"\"\n\n#: src/ne_props.c:364 src/ne_props.c:428\nmsgid \"Response exceeds maximum property count\"\nmsgstr \"\"\n\n#: src/ne_request.c:210\n#, fuzzy, c-format\nmsgid \"%s: connection was closed by proxy server\"\nmsgstr \"%s: erreur: impossible de se connecter  l'hte distant.\\n\"\n\n#: src/ne_request.c:213\n#, c-format\nmsgid \"%s: connection was closed by server\"\nmsgstr \"\"\n\n#: src/ne_request.c:218\n#, c-format\nmsgid \"%s: connection timed out\"\nmsgstr \"\"\n\n#: src/ne_request.c:321\n#, fuzzy, c-format\nmsgid \"Premature EOF in request body file\"\nmsgstr \"%s: erreur: impossible d'ouvrir le fichier de ressources: %s\\n\"\n\n#: src/ne_request.c:328\n#, fuzzy, c-format\nmsgid \"Failed reading request body file: %s\"\nmsgstr \"%s: erreur: impossible d'ouvrir le fichier de ressources: %s\\n\"\n\n#: src/ne_request.c:348\nmsgid \"offset invalid\"\nmsgstr \"\"\n\n#: src/ne_request.c:353\n#, fuzzy, c-format\nmsgid \"Could not seek to offset %s of request body file: %s\"\nmsgstr \"%s: erreur: impossible d'ouvrir le fichier de ressources: %s\\n\"\n\n#: src/ne_request.c:439\nmsgid \"Could not send request body\"\nmsgstr \"\"\n\n#: src/ne_request.c:466\n#, fuzzy\nmsgid \"Could not send chunked request terminator\"\nmsgstr \"%s: erreur: impossible de se connecter  l'hte distant.\\n\"\n\n#: src/ne_request.c:842\n#, fuzzy, c-format\nmsgid \"Could not parse redirect destination URL\"\nmsgstr \"%s: erreur: impossible d'ouvrir le fichier de ressources: %s\\n\"\n\n#: src/ne_request.c:848\n#, fuzzy, c-format\nmsgid \"Could not parse request target URI\"\nmsgstr \"%s: erreur: impossible d'ouvrir le fichier de ressources: %s\\n\"\n\n#: src/ne_request.c:1024\nmsgid \"Could not read chunk size\"\nmsgstr \"\"\n\n#: src/ne_request.c:1027\nmsgid \"Invalid chunk-size line\"\nmsgstr \"\"\n\n#: src/ne_request.c:1045\n#, fuzzy\nmsgid \"Could not parse chunk size\"\nmsgstr \"%s: erreur: impossible d'ouvrir le fichier de ressources: %s\\n\"\n\n#: src/ne_request.c:1085\nmsgid \"Could not read response body\"\nmsgstr \"\"\n\n#: src/ne_request.c:1101\n#, fuzzy\nmsgid \"Could not read chunk delimiter\"\nmsgstr \"%s: erreur: impossible d'ouvrir le fichier de ressources: %s\\n\"\n\n#: src/ne_request.c:1104\nmsgid \"Chunk delimiter was invalid\"\nmsgstr \"\"\n\n#: src/ne_request.c:1202\nmsgid \"Could not read status line\"\nmsgstr \"\"\n\n#: src/ne_request.c:1224\n#, fuzzy\nmsgid \"Could not parse response status line\"\nmsgstr \"%s: erreur: impossible d'ouvrir le fichier de ressources: %s\\n\"\n\n#: src/ne_request.c:1227\nmsgid \"Incompatible HTTP version\"\nmsgstr \"\"\n\n#: src/ne_request.c:1266\nmsgid \"Could not send request\"\nmsgstr \"\"\n\n#: src/ne_request.c:1308\n#, fuzzy\nmsgid \"Timed out reading interim responses\"\nmsgstr \"%s: erreur: impossible d'ouvrir le fichier de ressources: %s\\n\"\n\n#: src/ne_request.c:1337 src/ne_request.c:1354 src/ne_request.c:1364\nmsgid \"Error reading response headers\"\nmsgstr \"\"\n\n#: src/ne_request.c:1374\n#, c-format\nmsgid \"Response header too long\"\nmsgstr \"\"\n\n#: src/ne_request.c:1507\nmsgid \"Response exceeded maximum number of header fields\"\nmsgstr \"\"\n\n#: src/ne_request.c:1522\n#, fuzzy, c-format\nmsgid \"Could not resolve hostname `%s': %s\"\nmsgstr \"%s: erreur: impossible de trouver le nom de l'hte distant.\\n\"\n\n#: src/ne_request.c:1645\nmsgid \"Unknown transfer-coding in response\"\nmsgstr \"\"\n\n#: src/ne_request.c:1660\nmsgid \"Invalid Content-Length in response\"\nmsgstr \"\"\n\n#: src/ne_request.c:1734\n#, fuzzy, c-format\nmsgid \"Could not write to file: %s\"\nmsgstr \"%s: erreur: impossible d'ouvrir le fichier de ressources: %s\\n\"\n\n#: src/ne_request.c:1777\n#, c-format\nmsgid \"Response buffer size too small\"\nmsgstr \"\"\n\n#: src/ne_request.c:1845\n#, fuzzy, c-format\nmsgid \"Could not create SSL connection through proxy server: %s\"\nmsgstr \"%s: erreur: impossible de se connecter  l'hte distant.\\n\"\n\n#: src/ne_request.c:1884\n#, fuzzy, c-format\nmsgid \"Could not create socket\"\nmsgstr \"%s: erreur: impossible de se connecter  l'hte distant.\\n\"\n\n#: src/ne_request.c:1920\n#, fuzzy\nmsgid \"Could not connect to server\"\nmsgstr \"%s: erreur: impossible de se connecter  l'hte distant.\\n\"\n\n#: src/ne_request.c:1922\n#, fuzzy\nmsgid \"Could not connect to proxy server\"\nmsgstr \"%s: erreur: impossible de se connecter  l'hte distant.\\n\"\n\n#: src/ne_request.c:1965\n#, c-format\nmsgid \"Could not find IPv4 address of hostname %s for SOCKS v4 proxy\"\nmsgstr \"\"\n\n#: src/ne_request.c:2023\n#, fuzzy, c-format\nmsgid \"Could not establish connection from SOCKS proxy (%s:%u): %s\"\nmsgstr \"%s: erreur: impossible de se connecter  l'hte distant.\\n\"\n\n#: src/ne_session.c:236\n#, fuzzy\nmsgid \"Unknown error.\"\nmsgstr \"Erreur systme inconnue\"\n\n#: src/ne_session.c:615\n#, c-format\nmsgid \"Could not set minimum/maximum SSL/TLS versions\"\nmsgstr \"\"\n\n#: src/ne_session.c:622\n#, c-format\nmsgid \"SSL/TLS not enabled for the session\"\nmsgstr \"\"\n\n#: src/ne_session.c:653 src/ne_session.c:664\nmsgid \"[invalid date]\"\nmsgstr \"\"\n\n#: src/ne_session.c:686 src/ne_socket.c:747\n#, fuzzy, c-format\nmsgid \"SSL error: %s\"\nmsgstr \"\"\n\"%s: dans issue_error\\n\"\n\"%s\"\n\n#: src/ne_session.c:712\n#, fuzzy, c-format\nmsgid \"SSL handshake failed: %s\"\nmsgstr \"%s: erreur: impossible d'ouvrir le fichier de ressources: %s\\n\"\n\n#: src/ne_session.c:719\n#, fuzzy, c-format\nmsgid \"No server certificate: %s\"\nmsgstr \"%s: erreur: impossible d'ouvrir le fichier de ressources: %s\\n\"\n\n#: src/ne_socket.c:527 src/ne_socket.c:680 src/ne_socket.c:834\nmsgid \"Connection closed\"\nmsgstr \"\"\n\n#: src/ne_socket.c:685\nmsgid \"Retry operation\"\nmsgstr \"\"\n\n#: src/ne_socket.c:700 src/ne_socket.c:735 src/ne_socket.c:848\nmsgid \"Secure connection truncated\"\nmsgstr \"\"\n\n#: src/ne_socket.c:705\nmsgid \"Secure connection reset\"\nmsgstr \"\"\n\n#: src/ne_socket.c:710 src/ne_socket.c:718\nmsgid \"Handshake rejected - client certificate was requested\"\nmsgstr \"\"\n\n#: src/ne_socket.c:721\n#, fuzzy\nmsgid \"Handshake failed\"\nmsgstr \"%s: erreur: impossible d'ouvrir le fichier de ressources: %s\\n\"\n\n#: src/ne_socket.c:750\n#, c-format\nmsgid \"SSL error code %d/%d/%lu\"\nmsgstr \"\"\n\n#: src/ne_socket.c:839\n#, fuzzy, c-format\nmsgid \"SSL alert received: %s\"\nmsgstr \"\"\n\"%s: dans issue_error\\n\"\n\"%s\"\n\n#: src/ne_socket.c:860\nmsgid \"SSL socket read failed\"\nmsgstr \"\"\n\n#: src/ne_socket.c:864\nmsgid \" (client certificate was requested)\"\nmsgstr \"\"\n\n#: src/ne_socket.c:868\n#, fuzzy, c-format\nmsgid \"SSL error%s: %s\"\nmsgstr \"\"\n\"%s: dans issue_error\\n\"\n\"%s\"\n\n#: src/ne_socket.c:994\nmsgid \"Line too long\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1155 src/ne_socket.c:1161\nmsgid \"Host not found\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1404\nmsgid \"Connection timed out\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1603\nmsgid \"Socket descriptor number exceeds FD_SETSIZE\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1665\nmsgid \"Socket family not supported\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1825\nmsgid \"certificate is not yet valid\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1826\nmsgid \"certificate has expired\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1827\nmsgid \"certificate issued for a different hostname\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1828\nmsgid \"issuer is not trusted\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1829\nmsgid \"bad certificate chain\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1830\nmsgid \"certificate has been revoked\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1835\nmsgid \"Server certificate verification failed: \"\nmsgstr \"\"\n\n#: src/ne_socket.c:1913\n#, c-format\nmsgid \"SSL error: failed to set priority string at '%s'\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1968\nmsgid \"Client certificate verification failed\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1990\nmsgid \"SSL disabled due to lack of entropy\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1996\n#, fuzzy\nmsgid \"Could not create SSL structure\"\nmsgstr \"%s: erreur: impossible de se connecter  l'hte distant.\\n\"\n\n#: src/ne_socket.c:2210\nmsgid \"SSL server did not present certificate\"\nmsgstr \"\"\n\n#: src/ne_socket.c:2240\nmsgid \"Missing flags for socket shutdown\"\nmsgstr \"\"\n\n#: src/ne_socket.c:2258 src/ne_socket.c:2269 src/ne_socket.c:2284\nmsgid \"Incomplete TLS closure\"\nmsgstr \"\"\n\n#: src/ne_socks.c:65\nmsgid \"failure\"\nmsgstr \"\"\n\n#: src/ne_socks.c:68\nmsgid \"connection not permitted\"\nmsgstr \"\"\n\n#: src/ne_socks.c:71\nmsgid \"network unreachable\"\nmsgstr \"\"\n\n#: src/ne_socks.c:74\nmsgid \"host unreachable\"\nmsgstr \"\"\n\n#: src/ne_socks.c:77\nmsgid \"TTL expired\"\nmsgstr \"\"\n\n#: src/ne_socks.c:80\nmsgid \"command not supported\"\nmsgstr \"\"\n\n#: src/ne_socks.c:83\nmsgid \"address type not supported\"\nmsgstr \"\"\n\n#: src/ne_socks.c:86\n#, c-format\nmsgid \"%s: unrecognized error (%u)\"\nmsgstr \"\"\n\n#: src/ne_socks.c:128 src/ne_socks.c:328\n#, fuzzy\nmsgid \"Could not send message to proxy\"\nmsgstr \"%s: erreur: impossible de se connecter  l'hte distant.\\n\"\n\n#: src/ne_socks.c:133\n#, fuzzy\nmsgid \"Could not read initial response from proxy\"\nmsgstr \"%s: erreur: impossible d'ouvrir le fichier de ressources: %s\\n\"\n\n#: src/ne_socks.c:136\nmsgid \"Invalid version in proxy response\"\nmsgstr \"\"\n\n#: src/ne_socks.c:157\n#, fuzzy\nmsgid \"Could not send login message\"\nmsgstr \"%s: erreur: impossible d'ouvrir le fichier de ressources: %s\\n\"\n\n#: src/ne_socks.c:162\n#, fuzzy\nmsgid \"Could not read login reply\"\nmsgstr \"%s: erreur: impossible d'ouvrir le fichier de ressources: %s\\n\"\n\n#: src/ne_socks.c:165\nmsgid \"Invalid version in login reply\"\nmsgstr \"\"\n\n#: src/ne_socks.c:168\n#, fuzzy\nmsgid \"Authentication failed\"\nmsgstr \"%s: erreur: impossible d'ouvrir le fichier de ressources: %s\\n\"\n\n#: src/ne_socks.c:172\nmsgid \"No acceptable authentication method\"\nmsgstr \"\"\n\n#: src/ne_socks.c:174\nmsgid \"Unexpected authentication method chosen\"\nmsgstr \"\"\n\n#: src/ne_socks.c:210\n#, fuzzy\nmsgid \"Could not send connect request\"\nmsgstr \"%s: erreur: impossible de se connecter  l'hte distant.\\n\"\n\n#: src/ne_socks.c:215\n#, fuzzy\nmsgid \"Could not read connect reply\"\nmsgstr \"%s: erreur: impossible de se connecter  l'hte distant.\\n\"\n\n#: src/ne_socks.c:218\nmsgid \"Invalid version in connect reply\"\nmsgstr \"\"\n\n#: src/ne_socks.c:221 src/ne_socks.c:337\n#, fuzzy\nmsgid \"Could not connect\"\nmsgstr \"%s: erreur: impossible de se connecter  l'hte distant.\\n\"\n\n#: src/ne_socks.c:235\nmsgid \"Could not read FQDN length in connect reply\"\nmsgstr \"\"\n\n#: src/ne_socks.c:240\nmsgid \"Unknown address type in connect reply\"\nmsgstr \"\"\n\n#: src/ne_socks.c:245\n#, fuzzy\nmsgid \"Could not read address in connect reply\"\nmsgstr \"%s: erreur: impossible de se connecter  l'hte distant.\\n\"\n\n#: src/ne_socks.c:266\nmsgid \"request rejected or failed\"\nmsgstr \"\"\n\n#: src/ne_socks.c:269\n#, fuzzy\nmsgid \"could not establish connection to identd\"\nmsgstr \"%s: erreur: impossible de se connecter  l'hte distant.\\n\"\n\n#: src/ne_socks.c:272\nmsgid \"rejected due to identd user mismatch\"\nmsgstr \"\"\n\n#: src/ne_socks.c:275\n#, c-format\nmsgid \"%s: unrecognized failure (%u)\"\nmsgstr \"\"\n\n#: src/ne_socks.c:333\n#, fuzzy\nmsgid \"Could not read response from proxy\"\nmsgstr \"%s: erreur: impossible d'ouvrir le fichier de ressources: %s\\n\"\n\n#: src/ne_xml.c:190\n#, fuzzy, c-format\nmsgid \"XML parse error: %s\"\nmsgstr \"\"\n\"%s: erreur dans le fichier de ressources  la ligne %d:\\n\"\n\"%s\\n\"\n\n#: src/ne_xml.c:305\n#, fuzzy, c-format\nmsgid \"XML parse error at line %d: invalid element name\"\nmsgstr \"\"\n\"%s: erreur dans le fichier de ressources  la ligne %d:\\n\"\n\"%s\\n\"\n\n#: src/ne_xml.c:499\n#, fuzzy\nmsgid \"Unknown error\"\nmsgstr \"Erreur systme inconnue\"\n\n#: src/ne_xml.c:625\nmsgid \"Invalid Byte Order Mark\"\nmsgstr \"\"\n\n#: src/ne_xml.c:714\n#, fuzzy, c-format\nmsgid \"XML parse error at line %d: %s\"\nmsgstr \"\"\n\"%s: erreur dans le fichier de ressources  la ligne %d:\\n\"\n\"%s\\n\"\n\n#: src/ne_xmlreq.c:38\n#, fuzzy, c-format\nmsgid \"Could not parse response: %s\"\nmsgstr \"%s: erreur: impossible d'ouvrir le fichier de ressources: %s\\n\"\n\n#, fuzzy, c-format\n#~ msgid \"%s hash failed for Digest challenge\"\n#~ msgstr \"%s: erreur: impossible d'ouvrir le fichier de ressources: %s\\n\"\n\n#, fuzzy\n#~ msgid \"Could not read interim response headers\"\n#~ msgstr \"%s: erreur: impossible d'ouvrir le fichier de ressources: %s\\n\"\n\n#, fuzzy\n#~ msgid \"%s: %s\"\n#~ msgstr \"\"\n#~ \"%s: dans issue_error\\n\"\n#~ \"%s\"\n"
  },
  {
    "path": "po/ja.po",
    "content": "# The Japanese translation for sitecopy\n# Copyright (C) 2000 Nobuyuki Tsuchimura <tutimura@nn.iij4u.or.jp>\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: sitecopy 0.10.14\\n\"\n\"Report-Msgid-Bugs-To: https://github.com/notroj/neon\\n\"\n\"POT-Creation-Date: 2026-03-15 08:52+0000\\n\"\n\"PO-Revision-Date: 2001-01-16 07:32+0900\\n\"\n\"Last-Translator: Nobuyuki Tsuchimura <tutimura@nn.iij4u.or.jp>\\n\"\n\"Language-Team: ja\\n\"\n\"Language: \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=EUC-JP\\n\"\n\"Content-Transfer-Encoding: 8-bit\\n\"\n\n#: src/ne_207.c:231\n#, c-format\nmsgid \"\"\n\"Invalid HTTP status line in status element at line %d of response:\\n\"\n\"Status line was: %s\"\nmsgstr \"\"\n\n#: src/ne_auth.c:130\n#, fuzzy, c-format\nmsgid \"Could not authenticate to server: %s\"\nmsgstr \"ץС³Ǥޤ\"\n\n#: src/ne_auth.c:135\n#, fuzzy, c-format\nmsgid \"Could not authenticate to proxy server: %s\"\nmsgstr \"ץС³Ǥޤ\"\n\n#: src/ne_auth.c:338\n#, c-format\nmsgid \"rejected %s challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:379\nmsgid \"missing realm in Basic challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:393\nmsgid \"cannot handle Basic challenge for username containing colon\"\nmsgstr \"\"\n\n#: src/ne_auth.c:496\nmsgid \"invalid Negotiate token\"\nmsgstr \"\"\n\n#: src/ne_auth.c:519\n#, fuzzy\nmsgid \"GSSAPI authentication error: \"\nmsgstr \"%s ؤǧڤ %s ɬפǤ '%s':\\n\"\n\n#: src/ne_auth.c:532\n#, c-format\nmsgid \"GSSAPI failure (code %u)\"\nmsgstr \"\"\n\n#: src/ne_auth.c:567\nmsgid \"ignoring empty Negotiate continuation\"\nmsgstr \"\"\n\n#: src/ne_auth.c:582\n#, c-format\nmsgid \"Negotiate response verification failed: invalid response header token\"\nmsgstr \"\"\n\n#: src/ne_auth.c:604\n#, c-format\nmsgid \"Negotiate response verification failure: %s\"\nmsgstr \"\"\n\n#: src/ne_auth.c:668\n#, c-format\nmsgid \"SSPI response verification failed: invalid response header token\"\nmsgstr \"\"\n\n#: src/ne_auth.c:794\nmsgid \"unexpected token in NTLM challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:822\nmsgid \"malformed NTLM challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:840\n#, fuzzy\nmsgid \"could not handle NTLM challenge\"\nmsgstr \"chunk 礭ϤǤޤ\"\n\n#: src/ne_auth.c:908\n#, fuzzy\nmsgid \"could not handle non-ASCII username in Digest challenge\"\nmsgstr \"chunk 礭ϤǤޤ\"\n\n#: src/ne_auth.c:936\nmsgid \"unknown algorithm in Digest challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:943\nmsgid \"legacy Digest challenge not supported\"\nmsgstr \"\"\n\n#: src/ne_auth.c:947\nmsgid \"incompatible algorithm in Digest challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:951\nmsgid \"missing parameter in Digest challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:955\nmsgid \"initial Digest challenge was stale\"\nmsgstr \"\"\n\n#: src/ne_auth.c:962\nmsgid \"stale Digest challenge with new algorithm or realm\"\nmsgstr \"\"\n\n#: src/ne_auth.c:969\n#, c-format\nmsgid \"%s algorithm in Digest challenge not supported\"\nmsgstr \"\"\n\n#: src/ne_auth.c:985\n#, fuzzy\nmsgid \"could not parse domain in Digest challenge\"\nmsgstr \"chunk 礭ϤǤޤ\"\n\n#: src/ne_auth.c:992\n#, fuzzy\nmsgid \"cannot create client nonce for Digest challenge\"\nmsgstr \"chunk 礭ϤǤޤ\"\n\n#: src/ne_auth.c:1273\n#, c-format\nmsgid \"Digest mutual authentication failure: missing parameters\"\nmsgstr \"\"\n\n#: src/ne_auth.c:1278\n#, c-format\nmsgid \"Digest mutual authentication failure: client nonce mismatch\"\nmsgstr \"\"\n\n#: src/ne_auth.c:1287\n#, c-format\nmsgid \"Digest mutual authentication failure: could not parse nonce count\"\nmsgstr \"\"\n\n#: src/ne_auth.c:1292\n#, c-format\nmsgid \"Digest mutual authentication failure: nonce count mismatch (%u not %u)\"\nmsgstr \"\"\n\n#: src/ne_auth.c:1319\n#, c-format\nmsgid \"Digest mutual authentication failure: request-digest mismatch\"\nmsgstr \"\"\n\n#: src/ne_auth.c:1453\n#, c-format\nmsgid \"ignored %s challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:1550\n#, fuzzy\nmsgid \"could not parse challenge\"\nmsgstr \"chunk 礭ϤǤޤ\"\n\n#: src/ne_basic.c:98\n#, fuzzy, c-format\nmsgid \"Could not determine file size: %s\"\nmsgstr \"ե뤬ɤޤ: \"\n\n#: src/ne_basic.c:201\n#, c-format\nmsgid \"Response did not include requested range\"\nmsgstr \"\"\n\n#: src/ne_basic.c:236\n#, c-format\nmsgid \"Range is not satisfiable\"\nmsgstr \"\"\n\n#: src/ne_basic.c:241\n#, fuzzy, c-format\nmsgid \"Resource does not support ranged GET requests\"\nmsgstr \"Сեʬ򥵥ݡȤƤޤ\"\n\n#: src/ne_compress.c:184\n#, c-format\nmsgid \"%s: %s (code %d)\"\nmsgstr \"\"\n\n#: src/ne_compress.c:232\n#, fuzzy\nmsgid \"Could not inflate data\"\nmsgstr \"ե뤬ɤޤ: \"\n\n#: src/ne_compress.c:293\n#, fuzzy\nmsgid \"Could not initialize zlib\"\nmsgstr \"ե뤬񤱤ޤ: \"\n\n#: src/ne_gnutls.c:181\n#, c-format\nmsgid \"[unprintable:#%lu]\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:209\nmsgid \"[unprintable]\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:633\n#, c-format\nmsgid \"Failed to import private key: %s\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:920\nmsgid \"signed using insecure algorithm\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:923\n#, c-format\nmsgid \"unrecognized errors (%u)\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:965 src/ne_openssl.c:496\nmsgid \"Server certificate was missing commonName attribute in subject name\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:979\n#, fuzzy, c-format\nmsgid \"Could not verify server certificate: %s\"\nmsgstr \"ե뤬񤱤ޤ: %s\"\n\n#: src/ne_gnutls.c:998 src/ne_openssl.c:487\n#, c-format\nmsgid \"Certificate verification error: %s\"\nmsgstr \"\"\n\n#: src/ne_locks.c:640\nmsgid \"LOCK response missing Lock-Token header\"\nmsgstr \"\"\n\n#: src/ne_locks.c:815\n#, c-format\nmsgid \"Response missing activelock for %s\"\nmsgstr \"\"\n\n#: src/ne_locks.c:860\n#, c-format\nmsgid \"No activelock for <%s> returned in LOCK refresh response\"\nmsgstr \"\"\n\n#: src/ne_props.c:364 src/ne_props.c:428\nmsgid \"Response exceeds maximum property count\"\nmsgstr \"\"\n\n#: src/ne_request.c:210\n#, fuzzy, c-format\nmsgid \"%s: connection was closed by proxy server\"\nmsgstr \"%s: ³ץСڤޤ\"\n\n#: src/ne_request.c:213\n#, fuzzy, c-format\nmsgid \"%s: connection was closed by server\"\nmsgstr \"%s: ³Сڤޤ\"\n\n#: src/ne_request.c:218\n#, fuzzy, c-format\nmsgid \"%s: connection timed out\"\nmsgstr \"%s: ³ॢȤǤ\"\n\n#: src/ne_request.c:321\n#, fuzzy, c-format\nmsgid \"Premature EOF in request body file\"\nmsgstr \"ե뤬񤱤ޤ: %s\"\n\n#: src/ne_request.c:328\n#, fuzzy, c-format\nmsgid \"Failed reading request body file: %s\"\nmsgstr \"ե뤬񤱤ޤ: %s\"\n\n#: src/ne_request.c:348\nmsgid \"offset invalid\"\nmsgstr \"\"\n\n#: src/ne_request.c:353\n#, fuzzy, c-format\nmsgid \"Could not seek to offset %s of request body file: %s\"\nmsgstr \"ե뤬񤱤ޤ: %s\"\n\n#: src/ne_request.c:439\nmsgid \"Could not send request body\"\nmsgstr \"\"\n\n#: src/ne_request.c:466\n#, fuzzy\nmsgid \"Could not send chunked request terminator\"\nmsgstr \"ץС³Ǥޤ\"\n\n#: src/ne_request.c:842\n#, fuzzy, c-format\nmsgid \"Could not parse redirect destination URL\"\nmsgstr \"chunk 礭ϤǤޤ\"\n\n#: src/ne_request.c:848\n#, fuzzy, c-format\nmsgid \"Could not parse request target URI\"\nmsgstr \"chunk 礭ϤǤޤ\"\n\n#: src/ne_request.c:1024\nmsgid \"Could not read chunk size\"\nmsgstr \"chunk 礭ɤޤ\"\n\n#: src/ne_request.c:1027\nmsgid \"Invalid chunk-size line\"\nmsgstr \"\"\n\n#: src/ne_request.c:1045\nmsgid \"Could not parse chunk size\"\nmsgstr \"chunk 礭ϤǤޤ\"\n\n#: src/ne_request.c:1085\nmsgid \"Could not read response body\"\nmsgstr \"response body ɤޤ\"\n\n#: src/ne_request.c:1101\n#, fuzzy\nmsgid \"Could not read chunk delimiter\"\nmsgstr \"chunk 礭ɤޤ\"\n\n#: src/ne_request.c:1104\nmsgid \"Chunk delimiter was invalid\"\nmsgstr \"\"\n\n#: src/ne_request.c:1202\nmsgid \"Could not read status line\"\nmsgstr \"\"\n\n#: src/ne_request.c:1224\n#, fuzzy\nmsgid \"Could not parse response status line\"\nmsgstr \"response body ɤޤ\"\n\n#: src/ne_request.c:1227\nmsgid \"Incompatible HTTP version\"\nmsgstr \"\"\n\n#: src/ne_request.c:1266\nmsgid \"Could not send request\"\nmsgstr \"\"\n\n#: src/ne_request.c:1308\n#, fuzzy\nmsgid \"Timed out reading interim responses\"\nmsgstr \"response body ɤޤ\"\n\n#: src/ne_request.c:1337 src/ne_request.c:1354 src/ne_request.c:1364\nmsgid \"Error reading response headers\"\nmsgstr \"\"\n\n#: src/ne_request.c:1374\n#, c-format\nmsgid \"Response header too long\"\nmsgstr \"\"\n\n#: src/ne_request.c:1507\nmsgid \"Response exceeded maximum number of header fields\"\nmsgstr \"\"\n\n#: src/ne_request.c:1522\n#, fuzzy, c-format\nmsgid \"Could not resolve hostname `%s': %s\"\nmsgstr \"%s: 顼: СΥۥ̾ (%s)  IP ɥ쥹ѴǤޤ\\n\"\n\n#: src/ne_request.c:1645\nmsgid \"Unknown transfer-coding in response\"\nmsgstr \"\"\n\n#: src/ne_request.c:1660\nmsgid \"Invalid Content-Length in response\"\nmsgstr \"\"\n\n#: src/ne_request.c:1734\n#, c-format\nmsgid \"Could not write to file: %s\"\nmsgstr \"ե뤬񤱤ޤ: %s\"\n\n#: src/ne_request.c:1777\n#, c-format\nmsgid \"Response buffer size too small\"\nmsgstr \"\"\n\n#: src/ne_request.c:1845\n#, fuzzy, c-format\nmsgid \"Could not create SSL connection through proxy server: %s\"\nmsgstr \"ץС SSL ³Ǥޤ\"\n\n#: src/ne_request.c:1884\n#, fuzzy, c-format\nmsgid \"Could not create socket\"\nmsgstr \"ץС SSL ³Ǥޤ\"\n\n#: src/ne_request.c:1920\nmsgid \"Could not connect to server\"\nmsgstr \"ץС³Ǥޤ\"\n\n#: src/ne_request.c:1922\nmsgid \"Could not connect to proxy server\"\nmsgstr \"ץС³Ǥޤ\"\n\n#: src/ne_request.c:1965\n#, c-format\nmsgid \"Could not find IPv4 address of hostname %s for SOCKS v4 proxy\"\nmsgstr \"\"\n\n#: src/ne_request.c:2023\n#, fuzzy, c-format\nmsgid \"Could not establish connection from SOCKS proxy (%s:%u): %s\"\nmsgstr \"ץС SSL ³Ǥޤ\"\n\n#: src/ne_session.c:236\n#, fuzzy\nmsgid \"Unknown error.\"\nmsgstr \"̤ΤΥƥ२顼\"\n\n#: src/ne_session.c:615\n#, c-format\nmsgid \"Could not set minimum/maximum SSL/TLS versions\"\nmsgstr \"\"\n\n#: src/ne_session.c:622\n#, c-format\nmsgid \"SSL/TLS not enabled for the session\"\nmsgstr \"\"\n\n#: src/ne_session.c:653 src/ne_session.c:664\nmsgid \"[invalid date]\"\nmsgstr \"\"\n\n#: src/ne_session.c:686 src/ne_socket.c:747\n#, c-format\nmsgid \"SSL error: %s\"\nmsgstr \"\"\n\n#: src/ne_session.c:712\n#, fuzzy, c-format\nmsgid \"SSL handshake failed: %s\"\nmsgstr \"ե뤬񤱤ޤ: %s\"\n\n#: src/ne_session.c:719\n#, fuzzy, c-format\nmsgid \"No server certificate: %s\"\nmsgstr \"ե뤬񤱤ޤ: %s\"\n\n#: src/ne_socket.c:527 src/ne_socket.c:680 src/ne_socket.c:834\n#, fuzzy\nmsgid \"Connection closed\"\nmsgstr \"%s: ³Сڤޤ\"\n\n#: src/ne_socket.c:685\nmsgid \"Retry operation\"\nmsgstr \"\"\n\n#: src/ne_socket.c:700 src/ne_socket.c:735 src/ne_socket.c:848\n#, fuzzy\nmsgid \"Secure connection truncated\"\nmsgstr \"³ॢȡ\"\n\n#: src/ne_socket.c:705\n#, fuzzy\nmsgid \"Secure connection reset\"\nmsgstr \"³ॢȡ\"\n\n#: src/ne_socket.c:710 src/ne_socket.c:718\nmsgid \"Handshake rejected - client certificate was requested\"\nmsgstr \"\"\n\n#: src/ne_socket.c:721\n#, fuzzy\nmsgid \"Handshake failed\"\nmsgstr \"ե뤬񤱤ޤ: %s\"\n\n#: src/ne_socket.c:750\n#, c-format\nmsgid \"SSL error code %d/%d/%lu\"\nmsgstr \"\"\n\n#: src/ne_socket.c:839\n#, c-format\nmsgid \"SSL alert received: %s\"\nmsgstr \"\"\n\n#: src/ne_socket.c:860\nmsgid \"SSL socket read failed\"\nmsgstr \"\"\n\n#: src/ne_socket.c:864\nmsgid \" (client certificate was requested)\"\nmsgstr \"\"\n\n#: src/ne_socket.c:868\n#, c-format\nmsgid \"SSL error%s: %s\"\nmsgstr \"\"\n\n#: src/ne_socket.c:994\nmsgid \"Line too long\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1155 src/ne_socket.c:1161\nmsgid \"Host not found\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1404\n#, fuzzy\nmsgid \"Connection timed out\"\nmsgstr \"%s: ³ॢȤǤ\"\n\n#: src/ne_socket.c:1603\nmsgid \"Socket descriptor number exceeds FD_SETSIZE\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1665\nmsgid \"Socket family not supported\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1825\nmsgid \"certificate is not yet valid\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1826\nmsgid \"certificate has expired\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1827\nmsgid \"certificate issued for a different hostname\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1828\nmsgid \"issuer is not trusted\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1829\nmsgid \"bad certificate chain\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1830\nmsgid \"certificate has been revoked\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1835\nmsgid \"Server certificate verification failed: \"\nmsgstr \"\"\n\n#: src/ne_socket.c:1913\n#, c-format\nmsgid \"SSL error: failed to set priority string at '%s'\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1968\nmsgid \"Client certificate verification failed\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1990\nmsgid \"SSL disabled due to lack of entropy\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1996\n#, fuzzy\nmsgid \"Could not create SSL structure\"\nmsgstr \"ץС SSL ³Ǥޤ\"\n\n#: src/ne_socket.c:2210\nmsgid \"SSL server did not present certificate\"\nmsgstr \"\"\n\n#: src/ne_socket.c:2240\nmsgid \"Missing flags for socket shutdown\"\nmsgstr \"\"\n\n#: src/ne_socket.c:2258 src/ne_socket.c:2269 src/ne_socket.c:2284\nmsgid \"Incomplete TLS closure\"\nmsgstr \"\"\n\n#: src/ne_socks.c:65\nmsgid \"failure\"\nmsgstr \"\"\n\n#: src/ne_socks.c:68\n#, fuzzy\nmsgid \"connection not permitted\"\nmsgstr \"%s: ³ॢȤǤ\"\n\n#: src/ne_socks.c:71\nmsgid \"network unreachable\"\nmsgstr \"\"\n\n#: src/ne_socks.c:74\nmsgid \"host unreachable\"\nmsgstr \"\"\n\n#: src/ne_socks.c:77\nmsgid \"TTL expired\"\nmsgstr \"\"\n\n#: src/ne_socks.c:80\nmsgid \"command not supported\"\nmsgstr \"\"\n\n#: src/ne_socks.c:83\nmsgid \"address type not supported\"\nmsgstr \"\"\n\n#: src/ne_socks.c:86\n#, c-format\nmsgid \"%s: unrecognized error (%u)\"\nmsgstr \"\"\n\n#: src/ne_socks.c:128 src/ne_socks.c:328\n#, fuzzy\nmsgid \"Could not send message to proxy\"\nmsgstr \"response body ɤޤ\"\n\n#: src/ne_socks.c:133\n#, fuzzy\nmsgid \"Could not read initial response from proxy\"\nmsgstr \"response body ɤޤ\"\n\n#: src/ne_socks.c:136\nmsgid \"Invalid version in proxy response\"\nmsgstr \"\"\n\n#: src/ne_socks.c:157\n#, fuzzy\nmsgid \"Could not send login message\"\nmsgstr \"chunk 礭ɤޤ\"\n\n#: src/ne_socks.c:162\n#, fuzzy\nmsgid \"Could not read login reply\"\nmsgstr \"chunk 礭ɤޤ\"\n\n#: src/ne_socks.c:165\nmsgid \"Invalid version in login reply\"\nmsgstr \"\"\n\n#: src/ne_socks.c:168\n#, fuzzy\nmsgid \"Authentication failed\"\nmsgstr \"%s ؤǧڤ %s ɬפǤ '%s':\\n\"\n\n#: src/ne_socks.c:172\nmsgid \"No acceptable authentication method\"\nmsgstr \"\"\n\n#: src/ne_socks.c:174\nmsgid \"Unexpected authentication method chosen\"\nmsgstr \"\"\n\n#: src/ne_socks.c:210\n#, fuzzy\nmsgid \"Could not send connect request\"\nmsgstr \"ץС³Ǥޤ\"\n\n#: src/ne_socks.c:215\n#, fuzzy\nmsgid \"Could not read connect reply\"\nmsgstr \"ץС³Ǥޤ\"\n\n#: src/ne_socks.c:218\nmsgid \"Invalid version in connect reply\"\nmsgstr \"\"\n\n#: src/ne_socks.c:221 src/ne_socks.c:337\n#, fuzzy\nmsgid \"Could not connect\"\nmsgstr \"ץС³Ǥޤ\"\n\n#: src/ne_socks.c:235\nmsgid \"Could not read FQDN length in connect reply\"\nmsgstr \"\"\n\n#: src/ne_socks.c:240\nmsgid \"Unknown address type in connect reply\"\nmsgstr \"\"\n\n#: src/ne_socks.c:245\n#, fuzzy\nmsgid \"Could not read address in connect reply\"\nmsgstr \"response body ɤޤ\"\n\n#: src/ne_socks.c:266\nmsgid \"request rejected or failed\"\nmsgstr \"\"\n\n#: src/ne_socks.c:269\n#, fuzzy\nmsgid \"could not establish connection to identd\"\nmsgstr \"ץС³Ǥޤ\"\n\n#: src/ne_socks.c:272\nmsgid \"rejected due to identd user mismatch\"\nmsgstr \"\"\n\n#: src/ne_socks.c:275\n#, c-format\nmsgid \"%s: unrecognized failure (%u)\"\nmsgstr \"\"\n\n#: src/ne_socks.c:333\n#, fuzzy\nmsgid \"Could not read response from proxy\"\nmsgstr \"response body ɤޤ\"\n\n#: src/ne_xml.c:190\n#, fuzzy, c-format\nmsgid \"XML parse error: %s\"\nmsgstr \"\"\n\"%s: rcfile  %d ԤǴְäƤޤ:\\n\"\n\"%s\\n\"\n\n#: src/ne_xml.c:305\n#, fuzzy, c-format\nmsgid \"XML parse error at line %d: invalid element name\"\nmsgstr \"\"\n\"%s: rcfile  %d ԤǴְäƤޤ:\\n\"\n\"%s\\n\"\n\n#: src/ne_xml.c:499\n#, fuzzy\nmsgid \"Unknown error\"\nmsgstr \"̤ΤΥƥ२顼\"\n\n#: src/ne_xml.c:625\nmsgid \"Invalid Byte Order Mark\"\nmsgstr \"\"\n\n#: src/ne_xml.c:714\n#, fuzzy, c-format\nmsgid \"XML parse error at line %d: %s\"\nmsgstr \"\"\n\"%s: rcfile  %d ԤǴְäƤޤ:\\n\"\n\"%s\\n\"\n\n#: src/ne_xmlreq.c:38\n#, fuzzy, c-format\nmsgid \"Could not parse response: %s\"\nmsgstr \"response body ɤޤ\"\n\n#, fuzzy, c-format\n#~ msgid \"%s hash failed for Digest challenge\"\n#~ msgstr \"chunk 礭ϤǤޤ\"\n\n#, fuzzy\n#~ msgid \"Could not read interim response headers\"\n#~ msgstr \"response body ɤޤ\"\n\n#, fuzzy\n#~ msgid \"%s: %s\"\n#~ msgstr \"桼̾: %s\\n\"\n"
  },
  {
    "path": "po/ka.po",
    "content": "# Georgian translation for neon\n# Copyright (C) 2022, Temuri Doghonadze\n# This file is distributed under the same license as the neon package.\n# Temuri Doghonadze <temuri.doghonadze@gmail.com>, 2022.\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: neon-dev\\n\"\n\"Report-Msgid-Bugs-To: https://github.com/notroj/neon\\n\"\n\"POT-Creation-Date: 2026-03-15 08:52+0000\\n\"\n\"PO-Revision-Date: 2022-12-13 09:04+0100\\n\"\n\"Last-Translator: Temuri Doghonadze <temuri.doghonadze@gmail.com>\\n\"\n\"Language-Team: Georgian <(nothing)>\\n\"\n\"Language: ka\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"\n\"X-Generator: Poedit 3.2.2\\n\"\n\n#: src/ne_207.c:231\n#, c-format\nmsgid \"\"\n\"Invalid HTTP status line in status element at line %d of response:\\n\"\n\"Status line was: %s\"\nmsgstr \"\"\n\"არასწორი HTTP სტატუსის ხაზი სტატუსის ელემენტში პასუხის ხაზზე %d:\\n\"\n\"სტატუსის ხაზი: %s\"\n\n#: src/ne_auth.c:130\n#, c-format\nmsgid \"Could not authenticate to server: %s\"\nmsgstr \"სერვერთან ავთენტიკაციის შეცდომა: %s\"\n\n#: src/ne_auth.c:135\n#, c-format\nmsgid \"Could not authenticate to proxy server: %s\"\nmsgstr \"პროქსი სერვერთან ავთენტიკაციის შეცდომა: %s\"\n\n#: src/ne_auth.c:338\n#, c-format\nmsgid \"rejected %s challenge\"\nmsgstr \"%s გამოწვევა უარყოფილია\"\n\n#: src/ne_auth.c:379\nmsgid \"missing realm in Basic challenge\"\nmsgstr \"basic გამოწვევაში რეალმი მითითებული არაა\"\n\n#: src/ne_auth.c:393\nmsgid \"cannot handle Basic challenge for username containing colon\"\nmsgstr \"\"\n\"basic გამოწვევისთვის ორი წერტილის შემცველი მომხმარებლის სახელის დამუშავება \"\n\"შეუძლებელია\"\n\n#: src/ne_auth.c:496\nmsgid \"invalid Negotiate token\"\nmsgstr \"მოლაპარაკების კოდი არასწორია\"\n\n#: src/ne_auth.c:519\nmsgid \"GSSAPI authentication error: \"\nmsgstr \"GSSAPI ავთენტიკაციის შეცდომა: \"\n\n#: src/ne_auth.c:532\n#, c-format\nmsgid \"GSSAPI failure (code %u)\"\nmsgstr \"GSSAPI -ის ავარია (კოდი %u)\"\n\n#: src/ne_auth.c:567\nmsgid \"ignoring empty Negotiate continuation\"\nmsgstr \"ცარიელი მოლაპარაკების გაგრძელების იგნორირება\"\n\n#: src/ne_auth.c:582\n#, c-format\nmsgid \"Negotiate response verification failed: invalid response header token\"\nmsgstr \"\"\n\"მოლაპარაკების პასუხის გადამოწმების შეცდომა: პასუხის თავსართის კოდი არასწორია\"\n\n#: src/ne_auth.c:604\n#, c-format\nmsgid \"Negotiate response verification failure: %s\"\nmsgstr \"მოლაპარაკების პასუხის გადამოწმების შეცდომა: %s\"\n\n#: src/ne_auth.c:668\n#, c-format\nmsgid \"SSPI response verification failed: invalid response header token\"\nmsgstr \"SSPI პასუხის გადამოწმების შეცდომა: პასუხის თავსართის კოდი არასწორია\"\n\n#: src/ne_auth.c:794\n#, fuzzy\nmsgid \"unexpected token in NTLM challenge\"\nmsgstr \"%s გამოწვევა უარყოფილია\"\n\n#: src/ne_auth.c:822\n#, fuzzy\nmsgid \"malformed NTLM challenge\"\nmsgstr \"%s გამოწვევა იგნორირებულია\"\n\n#: src/ne_auth.c:840\n#, fuzzy\nmsgid \"could not handle NTLM challenge\"\nmsgstr \"გამოწვევის დამუშავების შეცდომა\"\n\n#: src/ne_auth.c:908\nmsgid \"could not handle non-ASCII username in Digest challenge\"\nmsgstr \"\"\n\"დაიჯესტის გამოწვევაში არა-ASCII მომხმარებლის სახელის დამუშავება შეუძლებელია\"\n\n#: src/ne_auth.c:936\nmsgid \"unknown algorithm in Digest challenge\"\nmsgstr \"დაიჯესტის გამოწვევის უცნობი ალგორითმი\"\n\n#: src/ne_auth.c:943\nmsgid \"legacy Digest challenge not supported\"\nmsgstr \"მოძველებული დაიჯესტის გამოწვევა მხარდაჭერილი არაა\"\n\n#: src/ne_auth.c:947\nmsgid \"incompatible algorithm in Digest challenge\"\nmsgstr \"დაიჯესტის გამოწვევის შეუთავსებელი ალგორითმი\"\n\n#: src/ne_auth.c:951\nmsgid \"missing parameter in Digest challenge\"\nmsgstr \"დაიჯესტის გამოწვევას პარამეტრი აკლია\"\n\n#: src/ne_auth.c:955\nmsgid \"initial Digest challenge was stale\"\nmsgstr \"საწყისი დაიჯესტის გამოწვევა გაჭედილია\"\n\n#: src/ne_auth.c:962\nmsgid \"stale Digest challenge with new algorithm or realm\"\nmsgstr \"გაჭედლი დაიჯესტის გამოწვევა ახალი ალგორითმით ან რეალმით\"\n\n#: src/ne_auth.c:969\n#, c-format\nmsgid \"%s algorithm in Digest challenge not supported\"\nmsgstr \"%s ალგორითმი დაიჯესტის გამოწვევაში მხარდაჭერილი არაა\"\n\n#: src/ne_auth.c:985\nmsgid \"could not parse domain in Digest challenge\"\nmsgstr \"დაიჯესტის გამოწვევაში დომენის დამუშავების შეცდომა\"\n\n#: src/ne_auth.c:992\n#, fuzzy\nmsgid \"cannot create client nonce for Digest challenge\"\nmsgstr \"დაიჯესტის გამოწვევაში დომენის დამუშავების შეცდომა\"\n\n#: src/ne_auth.c:1273\n#, c-format\nmsgid \"Digest mutual authentication failure: missing parameters\"\nmsgstr \"დაჯესტის ორმხრივი ავთენტიკაციის შეცდომა: არასაკმარისი პარამეტრებ\"\n\n#: src/ne_auth.c:1278\n#, c-format\nmsgid \"Digest mutual authentication failure: client nonce mismatch\"\nmsgstr \"დაიჯესტის ორმხრივი ავთენტიკაციის შეცდომა: კლიენტის nonce არ ემთხვევა\"\n\n#: src/ne_auth.c:1287\n#, c-format\nmsgid \"Digest mutual authentication failure: could not parse nonce count\"\nmsgstr \"\"\n\"დაიჯესტის ორმხრივი ავთენტიკაციის შეცდომა: nonce-ების რაოდენობის დამუშავების \"\n\"შეცდომა\"\n\n#: src/ne_auth.c:1292\n#, c-format\nmsgid \"Digest mutual authentication failure: nonce count mismatch (%u not %u)\"\nmsgstr \"\"\n\"დაიჯესტის ორმხრივი ავთენტიკაციის შეცდომა: nonce-ის რაოდენობა არ ემთხვევა (%u \"\n\"და არა %u)\"\n\n#: src/ne_auth.c:1319\n#, c-format\nmsgid \"Digest mutual authentication failure: request-digest mismatch\"\nmsgstr \"დაიჯესტის ორმხრივი ავთენტიკაციის შეცდომა: request-digest არ ემთხვევა\"\n\n#: src/ne_auth.c:1453\n#, c-format\nmsgid \"ignored %s challenge\"\nmsgstr \"%s გამოწვევა იგნორირებულია\"\n\n#: src/ne_auth.c:1550\nmsgid \"could not parse challenge\"\nmsgstr \"გამოწვევის დამუშავების შეცდომა\"\n\n#: src/ne_basic.c:98\n#, c-format\nmsgid \"Could not determine file size: %s\"\nmsgstr \"ფაილის ზომის განსაზღვრის შეცდომა: %s\"\n\n#: src/ne_basic.c:201\n#, c-format\nmsgid \"Response did not include requested range\"\nmsgstr \"პასუხი მოთხოვნილ დიაპაზონს არ შეიცავს\"\n\n#: src/ne_basic.c:236\n#, c-format\nmsgid \"Range is not satisfiable\"\nmsgstr \"დაპაზონი დამაკმაყოფილებელი არაა\"\n\n#: src/ne_basic.c:241\n#, c-format\nmsgid \"Resource does not support ranged GET requests\"\nmsgstr \"რესურსს დიაპაზონის შემცველ GETი მოთხოვნების მხარდაჭერა არ გააჩნია\"\n\n#: src/ne_compress.c:184\n#, c-format\nmsgid \"%s: %s (code %d)\"\nmsgstr \"%s: %s (კოდი %d)\"\n\n#: src/ne_compress.c:232\nmsgid \"Could not inflate data\"\nmsgstr \"მონაცემების შებერვის შეცდოა\"\n\n#: src/ne_compress.c:293\nmsgid \"Could not initialize zlib\"\nmsgstr \"ZLib-ის ინიციალიზაციის შეცდომა\"\n\n#: src/ne_gnutls.c:181\n#, c-format\nmsgid \"[unprintable:#%lu]\"\nmsgstr \"[არა-ბეჭდვადი:#%lu]\"\n\n#: src/ne_gnutls.c:209\nmsgid \"[unprintable]\"\nmsgstr \"[არადაბეჭდვადი]\"\n\n#: src/ne_gnutls.c:633\n#, c-format\nmsgid \"Failed to import private key: %s\"\nmsgstr \"სერვერის პირადი გასაღების შემოტანის შეცდომა: %s\"\n\n#: src/ne_gnutls.c:920\nmsgid \"signed using insecure algorithm\"\nmsgstr \"ხელმოწერილია დაუცველი ალგორითმით\"\n\n#: src/ne_gnutls.c:923\n#, c-format\nmsgid \"unrecognized errors (%u)\"\nmsgstr \"უცნობი შეცდომები (%u0)\"\n\n#: src/ne_gnutls.c:965 src/ne_openssl.c:496\nmsgid \"Server certificate was missing commonName attribute in subject name\"\nmsgstr \"სერვერის სერტიფიკატს თემის სახელში commonName ატრიბუტი აკლია\"\n\n#: src/ne_gnutls.c:979\n#, c-format\nmsgid \"Could not verify server certificate: %s\"\nmsgstr \"სერვერის სერტიფიკატის გადამოწმების შეცდომა: %s\"\n\n#: src/ne_gnutls.c:998 src/ne_openssl.c:487\n#, c-format\nmsgid \"Certificate verification error: %s\"\nmsgstr \"სერტიფიკატის გადამოწმების შეცდომა: %s\"\n\n#: src/ne_locks.c:640\nmsgid \"LOCK response missing Lock-Token header\"\nmsgstr \"LOCK პასუხს თავსართი Lock-Token აკლია\"\n\n#: src/ne_locks.c:815\n#, c-format\nmsgid \"Response missing activelock for %s\"\nmsgstr \"პასუხს %s-სთვის activelock აკლია\"\n\n#: src/ne_locks.c:860\n#, c-format\nmsgid \"No activelock for <%s> returned in LOCK refresh response\"\nmsgstr \"LOCK-ის განახლების პასუხში <%s>-ის activelock არ დაბრუნებულა\"\n\n#: src/ne_props.c:364 src/ne_props.c:428\nmsgid \"Response exceeds maximum property count\"\nmsgstr \"პასუხი თვისებების მაქსიმალურ რაოდენობას აჭარბებს\"\n\n#: src/ne_request.c:210\n#, c-format\nmsgid \"%s: connection was closed by proxy server\"\nmsgstr \"%s: შეერთება დახურულია პროქსი სერვერის მიერ\"\n\n#: src/ne_request.c:213\n#, c-format\nmsgid \"%s: connection was closed by server\"\nmsgstr \"%s შეერთება დახურულია სერვერის მიერ\"\n\n#: src/ne_request.c:218\n#, c-format\nmsgid \"%s: connection timed out\"\nmsgstr \"%s: შეერთების მოლოდინის ვადა ამოიწურა\"\n\n#: src/ne_request.c:321\n#, c-format\nmsgid \"Premature EOF in request body file\"\nmsgstr \"ნაადრევი EOF მოთხოვნის სხეულის ფაილში\"\n\n#: src/ne_request.c:328\n#, c-format\nmsgid \"Failed reading request body file: %s\"\nmsgstr \"მოთხოვნის სხეულის ფაილის წაკითხვის შეცდომა: %s\"\n\n#: src/ne_request.c:348\nmsgid \"offset invalid\"\nmsgstr \"წანაცვლება არასწორია\"\n\n#: src/ne_request.c:353\n#, c-format\nmsgid \"Could not seek to offset %s of request body file: %s\"\nmsgstr \"მოთხოვნის სხეულის ფაილში %s წანაცვლებაზე გადახვევის შეცდომა: %s\"\n\n#: src/ne_request.c:439\nmsgid \"Could not send request body\"\nmsgstr \"მოთხოვნის სხეულის გაგზავნის შეცდომა\"\n\n#: src/ne_request.c:466\nmsgid \"Could not send chunked request terminator\"\nmsgstr \"ნაგლეჯების შემცველი მოთხოვნის დამსრულებლის გაგზავნის შეცდომა\"\n\n#: src/ne_request.c:842\n#, c-format\nmsgid \"Could not parse redirect destination URL\"\nmsgstr \"გადამისამართების სამიზნე URL-ის დამუშავების შეცდომა\"\n\n#: src/ne_request.c:848\n#, fuzzy, c-format\nmsgid \"Could not parse request target URI\"\nmsgstr \"გადამისამართების სამიზნე URL-ის დამუშავების შეცდომა\"\n\n#: src/ne_request.c:1024\nmsgid \"Could not read chunk size\"\nmsgstr \"ნაგლეჯის ზომის წაკითხვის შეცდომა\"\n\n#: src/ne_request.c:1027\nmsgid \"Invalid chunk-size line\"\nmsgstr \"\"\n\n#: src/ne_request.c:1045\nmsgid \"Could not parse chunk size\"\nmsgstr \"ნაგლეჯის ზომის დამუშავების შეცდოა\"\n\n#: src/ne_request.c:1085\nmsgid \"Could not read response body\"\nmsgstr \"პასუხის სხეულის დამუშავების შეცდომა\"\n\n#: src/ne_request.c:1101\nmsgid \"Could not read chunk delimiter\"\nmsgstr \"ნაგლეჯის გამყოფის წაკითხვის შეცდომა\"\n\n#: src/ne_request.c:1104\nmsgid \"Chunk delimiter was invalid\"\nmsgstr \"ნაგლეჯის გამყოფი არასწორია\"\n\n#: src/ne_request.c:1202\nmsgid \"Could not read status line\"\nmsgstr \"სტატუსის ხაზის წაკითხვა შეუძლებელია\"\n\n#: src/ne_request.c:1224\nmsgid \"Could not parse response status line\"\nmsgstr \"პასუხის სტატუსის ხაზის წაკითხვის შეცდომა\"\n\n#: src/ne_request.c:1227\nmsgid \"Incompatible HTTP version\"\nmsgstr \"\"\n\n#: src/ne_request.c:1266\nmsgid \"Could not send request\"\nmsgstr \"მოთხოვნის გაგზავნა შეუძლებელია\"\n\n#: src/ne_request.c:1308\n#, fuzzy\nmsgid \"Timed out reading interim responses\"\nmsgstr \"მეტისმეტად ბევრი შუალედური პასუხი\"\n\n#: src/ne_request.c:1337 src/ne_request.c:1354 src/ne_request.c:1364\nmsgid \"Error reading response headers\"\nmsgstr \"პასუხის თავსართების წაკითხვის შეცდომა\"\n\n#: src/ne_request.c:1374\n#, c-format\nmsgid \"Response header too long\"\nmsgstr \"პასუხის თავსართი მეტისმეტად გრძელია\"\n\n#: src/ne_request.c:1507\nmsgid \"Response exceeded maximum number of header fields\"\nmsgstr \"პასუხის თავსართის ველების მაქსიმალურ რიცხვს სცდება\"\n\n#: src/ne_request.c:1522\n#, c-format\nmsgid \"Could not resolve hostname `%s': %s\"\nmsgstr \"ჰოსტის სახელის '%s' ამოხსნის შეცდომა: %s\"\n\n#: src/ne_request.c:1645\nmsgid \"Unknown transfer-coding in response\"\nmsgstr \"პასუხის transfer-code არასწორია\"\n\n#: src/ne_request.c:1660\nmsgid \"Invalid Content-Length in response\"\nmsgstr \"პასუხის Content-Length არასწორია\"\n\n#: src/ne_request.c:1734\n#, c-format\nmsgid \"Could not write to file: %s\"\nmsgstr \"ფაილში ჩაწერის შეცდომა: %s\"\n\n#: src/ne_request.c:1777\n#, fuzzy, c-format\nmsgid \"Response buffer size too small\"\nmsgstr \"პასუხის თავსართი მეტისმეტად გრძელია\"\n\n#: src/ne_request.c:1845\n#, c-format\nmsgid \"Could not create SSL connection through proxy server: %s\"\nmsgstr \"პროქსის გავლით SSL შეერთების შექნის შეცდომა: %s\"\n\n#: src/ne_request.c:1884\n#, c-format\nmsgid \"Could not create socket\"\nmsgstr \"სოკეტის შექმნის შეცდომა\"\n\n#: src/ne_request.c:1920\nmsgid \"Could not connect to server\"\nmsgstr \"სერვერთან მიერთების პრობლემა\"\n\n#: src/ne_request.c:1922\nmsgid \"Could not connect to proxy server\"\nmsgstr \"პროქსი სერვერთან დაკავშირების შეცდომა\"\n\n#: src/ne_request.c:1965\n#, c-format\nmsgid \"Could not find IPv4 address of hostname %s for SOCKS v4 proxy\"\nmsgstr \"\"\n\"SOCKS v4 პროქსისთვის ჰოსტის სახელის %s IPv4 მისამართის აღმოჩენა შეუძლებელია\"\n\n#: src/ne_request.c:2023\n#, c-format\nmsgid \"Could not establish connection from SOCKS proxy (%s:%u): %s\"\nmsgstr \"SOCKS პროქსიდან (%s:%u) მიერთების დამყარების შეცდომა: %s\"\n\n#: src/ne_session.c:236\n#, fuzzy\nmsgid \"Unknown error.\"\nmsgstr \"უცნობი შეცდომა\"\n\n#: src/ne_session.c:615\n#, c-format\nmsgid \"Could not set minimum/maximum SSL/TLS versions\"\nmsgstr \"\"\n\n#: src/ne_session.c:622\n#, c-format\nmsgid \"SSL/TLS not enabled for the session\"\nmsgstr \"\"\n\n#: src/ne_session.c:653 src/ne_session.c:664\nmsgid \"[invalid date]\"\nmsgstr \"[არასწორი თარიღი]\"\n\n#: src/ne_session.c:686 src/ne_socket.c:747\n#, c-format\nmsgid \"SSL error: %s\"\nmsgstr \"SSL-ის შეცდომა: %s\"\n\n#: src/ne_session.c:712\n#, c-format\nmsgid \"SSL handshake failed: %s\"\nmsgstr \"SSL მიმოცვლის შეცდომა: %s\"\n\n#: src/ne_session.c:719\n#, fuzzy, c-format\nmsgid \"No server certificate: %s\"\nmsgstr \"სერვერის სერტიფიკატის გადამოწმების შეცდომა: %s\"\n\n#: src/ne_socket.c:527 src/ne_socket.c:680 src/ne_socket.c:834\nmsgid \"Connection closed\"\nmsgstr \"კავშირი დახურულია\"\n\n#: src/ne_socket.c:685\nmsgid \"Retry operation\"\nmsgstr \"ოპერაციის თავიდან ცდა\"\n\n#: src/ne_socket.c:700 src/ne_socket.c:735 src/ne_socket.c:848\nmsgid \"Secure connection truncated\"\nmsgstr \"დაცული შეერთება წაკვეთილია\"\n\n#: src/ne_socket.c:705\nmsgid \"Secure connection reset\"\nmsgstr \"დაცული შეერთება გაწყდა\"\n\n#: src/ne_socket.c:710 src/ne_socket.c:718\n#, fuzzy\nmsgid \"Handshake rejected - client certificate was requested\"\nmsgstr \"SSL მიმოცვლის შეცდომა. მოთხოვნილი კლიენტის სერტიფიკატი: %s\"\n\n#: src/ne_socket.c:721\n#, fuzzy\nmsgid \"Handshake failed\"\nmsgstr \"SSL მიმოცვლის შეცდომა: %s\"\n\n#: src/ne_socket.c:750\n#, c-format\nmsgid \"SSL error code %d/%d/%lu\"\nmsgstr \"SSL -ის შეცდომის კოდი %d/%d/%lu\"\n\n#: src/ne_socket.c:839\n#, c-format\nmsgid \"SSL alert received: %s\"\nmsgstr \"SSL გაფრთხილება მიღებულია: %s\"\n\n#: src/ne_socket.c:860\nmsgid \"SSL socket read failed\"\nmsgstr \"SSL სოკეტის წაკითხვის შეცდომა\"\n\n#: src/ne_socket.c:864\n#, fuzzy\nmsgid \" (client certificate was requested)\"\nmsgstr \"SSL მიმოცვლის შეცდომა. მოთხოვნილი კლიენტის სერტიფიკატი: %s\"\n\n#: src/ne_socket.c:868\n#, fuzzy, c-format\nmsgid \"SSL error%s: %s\"\nmsgstr \"SSL-ის შეცდომა: %s\"\n\n#: src/ne_socket.c:994\nmsgid \"Line too long\"\nmsgstr \"ხაზი ძალიან გრძელია\"\n\n#: src/ne_socket.c:1155 src/ne_socket.c:1161\nmsgid \"Host not found\"\nmsgstr \"ჰოსტი ნაპოვნი არაა\"\n\n#: src/ne_socket.c:1404\nmsgid \"Connection timed out\"\nmsgstr \"კავშირის ვადა გავიდა\"\n\n#: src/ne_socket.c:1603\nmsgid \"Socket descriptor number exceeds FD_SETSIZE\"\nmsgstr \"სოკეტის დესკრიპტორის ნომერი FD_SETSIZE-ს სცილდება\"\n\n#: src/ne_socket.c:1665\nmsgid \"Socket family not supported\"\nmsgstr \"სოკეტის ოჯახი მხარდაჭერილი არაა\"\n\n#: src/ne_socket.c:1825\nmsgid \"certificate is not yet valid\"\nmsgstr \"სერტიფიკატი ჯერ არასწორია\"\n\n#: src/ne_socket.c:1826\nmsgid \"certificate has expired\"\nmsgstr \"სერტიფიკატი ვადაგასულია\"\n\n#: src/ne_socket.c:1827\nmsgid \"certificate issued for a different hostname\"\nmsgstr \"სერტიფიკატი სხვა ჰოსტის სახელს ეკუთვნის\"\n\n#: src/ne_socket.c:1828\nmsgid \"issuer is not trusted\"\nmsgstr \"გამომცემელი სანდო არაა\"\n\n#: src/ne_socket.c:1829\nmsgid \"bad certificate chain\"\nmsgstr \"სერტიფიკატების არასწორი ჯაჭვი\"\n\n#: src/ne_socket.c:1830\nmsgid \"certificate has been revoked\"\nmsgstr \"სერტიფიკატი გაუქმებულია\"\n\n#: src/ne_socket.c:1835\nmsgid \"Server certificate verification failed: \"\nmsgstr \"სერვერის სერტიფიკატის გადამოწმების შეცდომა: \"\n\n#: src/ne_socket.c:1913\n#, c-format\nmsgid \"SSL error: failed to set priority string at '%s'\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1968\nmsgid \"Client certificate verification failed\"\nmsgstr \"კლიენტის სერტიფიკატის შემოწმების შეცდომა\"\n\n#: src/ne_socket.c:1990\nmsgid \"SSL disabled due to lack of entropy\"\nmsgstr \"ენტროპიის ნაკლებობის გამო SSL-ი გათიშულია\"\n\n#: src/ne_socket.c:1996\nmsgid \"Could not create SSL structure\"\nmsgstr \"SSL სტრუქტურის შექმნის შეცდომა\"\n\n#: src/ne_socket.c:2210\nmsgid \"SSL server did not present certificate\"\nmsgstr \"SSL სერვერმა სერტიფიკატი არ წარმოადგინა\"\n\n#: src/ne_socket.c:2240\nmsgid \"Missing flags for socket shutdown\"\nmsgstr \"სოკეტის გასათიშად საჭირო ალმები არ არსებობს\"\n\n#: src/ne_socket.c:2258 src/ne_socket.c:2269 src/ne_socket.c:2284\nmsgid \"Incomplete TLS closure\"\nmsgstr \"TLS-ს არასრული დახურვა\"\n\n#: src/ne_socks.c:65\nmsgid \"failure\"\nmsgstr \"შეცდომა\"\n\n#: src/ne_socks.c:68\nmsgid \"connection not permitted\"\nmsgstr \"მიერთება ნებადართული არაა\"\n\n#: src/ne_socks.c:71\nmsgid \"network unreachable\"\nmsgstr \"ქსელი მიუწვდომელია\"\n\n#: src/ne_socks.c:74\nmsgid \"host unreachable\"\nmsgstr \"ჰოსტი მიუწვდომელია\"\n\n#: src/ne_socks.c:77\nmsgid \"TTL expired\"\nmsgstr \"TTL-ს ვადა გაუვიდა\"\n\n#: src/ne_socks.c:80\nmsgid \"command not supported\"\nmsgstr \"ბრძანება მხარდაჭერილი არაა\"\n\n#: src/ne_socks.c:83\nmsgid \"address type not supported\"\nmsgstr \"მისამართის ტიპი მხარდაუჭერელია\"\n\n#: src/ne_socks.c:86\n#, c-format\nmsgid \"%s: unrecognized error (%u)\"\nmsgstr \"%s: უცნობი შეცდომა (%u)\"\n\n#: src/ne_socks.c:128 src/ne_socks.c:328\nmsgid \"Could not send message to proxy\"\nmsgstr \"პროქსისთვის შეტყობინების გაგზავნა შეუძლებელია\"\n\n#: src/ne_socks.c:133\nmsgid \"Could not read initial response from proxy\"\nmsgstr \"პროქსიდან საწყისი პასუხის წაკითხვის შეცდომა\"\n\n#: src/ne_socks.c:136\nmsgid \"Invalid version in proxy response\"\nmsgstr \"არასწორი ვერსია პროქსის პასუხში\"\n\n#: src/ne_socks.c:157\nmsgid \"Could not send login message\"\nmsgstr \"შესვლის შეტყობინების გაგზავნის შეცდომა\"\n\n#: src/ne_socks.c:162\nmsgid \"Could not read login reply\"\nmsgstr \"შესვლის პასუხის წაკითხვის შეცდომა\"\n\n#: src/ne_socks.c:165\nmsgid \"Invalid version in login reply\"\nmsgstr \"არასწორი ვერსია შესვლის პასუხში\"\n\n#: src/ne_socks.c:168\nmsgid \"Authentication failed\"\nmsgstr \"ავთენტიფიკაცია ვერ მოხერდა\"\n\n#: src/ne_socks.c:172\nmsgid \"No acceptable authentication method\"\nmsgstr \"დამაკმაყოფილებელი ავთენტიკაციის მეთოდის გარეშე\"\n\n#: src/ne_socks.c:174\nmsgid \"Unexpected authentication method chosen\"\nmsgstr \"არჩეულია მოულოდნელი ავთენტიკაციის მეთოდი\"\n\n#: src/ne_socks.c:210\nmsgid \"Could not send connect request\"\nmsgstr \"შეერთების მოთხოვნის გაგზავნის შეცდომა\"\n\n#: src/ne_socks.c:215\nmsgid \"Could not read connect reply\"\nmsgstr \"მიერთების პასუხის წაკითხვის შეცდომა\"\n\n#: src/ne_socks.c:218\nmsgid \"Invalid version in connect reply\"\nmsgstr \"არასწორი ვერსია მიერთების პასუხში\"\n\n#: src/ne_socks.c:221 src/ne_socks.c:337\nmsgid \"Could not connect\"\nmsgstr \"მიერთების პრობლემა\"\n\n#: src/ne_socks.c:235\nmsgid \"Could not read FQDN length in connect reply\"\nmsgstr \"მიერთების პასუხში FQDN-ის სიგრძის წაკითხვის შეცდომა\"\n\n#: src/ne_socks.c:240\nmsgid \"Unknown address type in connect reply\"\nmsgstr \"მისამართის არასწორი ტიპი მიერთების პასუხში\"\n\n#: src/ne_socks.c:245\nmsgid \"Could not read address in connect reply\"\nmsgstr \"მიერთების პასუხიდან მისამართის წაკითხვის შეცდომა\"\n\n#: src/ne_socks.c:266\nmsgid \"request rejected or failed\"\nmsgstr \"მოთხოვნა უარყოფილი ან ავარიულია\"\n\n#: src/ne_socks.c:269\nmsgid \"could not establish connection to identd\"\nmsgstr \"identd-სთან მიერთების შეცდომა\"\n\n#: src/ne_socks.c:272\nmsgid \"rejected due to identd user mismatch\"\nmsgstr \"უარყოფილია identd-ის მომხმარებლის არ-დამთხვევის გამო\"\n\n#: src/ne_socks.c:275\n#, c-format\nmsgid \"%s: unrecognized failure (%u)\"\nmsgstr \"%s: უცნობი ავარია (%u)\"\n\n#: src/ne_socks.c:333\nmsgid \"Could not read response from proxy\"\nmsgstr \"პროქსის პასუხის წაკითხვის შეცდომა\"\n\n#: src/ne_xml.c:190\n#, fuzzy, c-format\nmsgid \"XML parse error: %s\"\nmsgstr \"XML -ის დამუშავების შეცდომა ხაზზე %d: %s\"\n\n#: src/ne_xml.c:305\n#, c-format\nmsgid \"XML parse error at line %d: invalid element name\"\nmsgstr \"XML-ის პასუხის შეცდომა ხაზზე %d: ელემენტის არასწორი სახელი\"\n\n#: src/ne_xml.c:499\nmsgid \"Unknown error\"\nmsgstr \"უცნობი შეცდომა\"\n\n#: src/ne_xml.c:625\nmsgid \"Invalid Byte Order Mark\"\nmsgstr \"ბაიტების მიმდევრობის არასწორი ნიშანი\"\n\n#: src/ne_xml.c:714\n#, c-format\nmsgid \"XML parse error at line %d: %s\"\nmsgstr \"XML -ის დამუშავების შეცდომა ხაზზე %d: %s\"\n\n#: src/ne_xmlreq.c:38\n#, c-format\nmsgid \"Could not parse response: %s\"\nmsgstr \"პასუხის დამუშავების შეცდომა: %s\"\n\n#, fuzzy, c-format\n#~ msgid \"%s hash failed for Digest challenge\"\n#~ msgstr \"დაიჯესტის გამოწვევას პარამეტრი აკლია\"\n\n#, c-format\n#~ msgid \"Server did not send certificate chain\"\n#~ msgstr \"სერვერმა სერტიფიკატის ჯაჭვი არ გამოაგზავნა\"\n\n#~ msgid \"Could not read status line (TLS client certificate was requested)\"\n#~ msgstr \"\"\n#~ \"სტატუსის ხაზის წაკითხვა შეუძლებელია (მოთხოვნილი იყო TLS კლიენტის \"\n#~ \"სერტიფიკატი)\"\n\n#~ msgid \"Could not read interim response headers\"\n#~ msgstr \"შუალედური პასუხის თავსართების წაკითხვის შეცდომა\"\n"
  },
  {
    "path": "po/neon.pot",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER\n# This file is distributed under the same license as the PACKAGE package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PACKAGE VERSION\\n\"\n\"Report-Msgid-Bugs-To: https://github.com/notroj/neon\\n\"\n\"POT-Creation-Date: 2026-03-15 08:52+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language-Team: LANGUAGE <LL@li.org>\\n\"\n\"Language: \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=CHARSET\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: src/ne_207.c:231\n#, c-format\nmsgid \"\"\n\"Invalid HTTP status line in status element at line %d of response:\\n\"\n\"Status line was: %s\"\nmsgstr \"\"\n\n#: src/ne_auth.c:130\n#, c-format\nmsgid \"Could not authenticate to server: %s\"\nmsgstr \"\"\n\n#: src/ne_auth.c:135\n#, c-format\nmsgid \"Could not authenticate to proxy server: %s\"\nmsgstr \"\"\n\n#: src/ne_auth.c:338\n#, c-format\nmsgid \"rejected %s challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:379\nmsgid \"missing realm in Basic challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:393\nmsgid \"cannot handle Basic challenge for username containing colon\"\nmsgstr \"\"\n\n#: src/ne_auth.c:496\nmsgid \"invalid Negotiate token\"\nmsgstr \"\"\n\n#: src/ne_auth.c:519\nmsgid \"GSSAPI authentication error: \"\nmsgstr \"\"\n\n#: src/ne_auth.c:532\n#, c-format\nmsgid \"GSSAPI failure (code %u)\"\nmsgstr \"\"\n\n#: src/ne_auth.c:567\nmsgid \"ignoring empty Negotiate continuation\"\nmsgstr \"\"\n\n#: src/ne_auth.c:582\n#, c-format\nmsgid \"Negotiate response verification failed: invalid response header token\"\nmsgstr \"\"\n\n#: src/ne_auth.c:604\n#, c-format\nmsgid \"Negotiate response verification failure: %s\"\nmsgstr \"\"\n\n#: src/ne_auth.c:668\n#, c-format\nmsgid \"SSPI response verification failed: invalid response header token\"\nmsgstr \"\"\n\n#: src/ne_auth.c:794\nmsgid \"unexpected token in NTLM challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:822\nmsgid \"malformed NTLM challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:840\nmsgid \"could not handle NTLM challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:908\nmsgid \"could not handle non-ASCII username in Digest challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:936\nmsgid \"unknown algorithm in Digest challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:943\nmsgid \"legacy Digest challenge not supported\"\nmsgstr \"\"\n\n#: src/ne_auth.c:947\nmsgid \"incompatible algorithm in Digest challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:951\nmsgid \"missing parameter in Digest challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:955\nmsgid \"initial Digest challenge was stale\"\nmsgstr \"\"\n\n#: src/ne_auth.c:962\nmsgid \"stale Digest challenge with new algorithm or realm\"\nmsgstr \"\"\n\n#: src/ne_auth.c:969\n#, c-format\nmsgid \"%s algorithm in Digest challenge not supported\"\nmsgstr \"\"\n\n#: src/ne_auth.c:985\nmsgid \"could not parse domain in Digest challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:992\nmsgid \"cannot create client nonce for Digest challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:1273\n#, c-format\nmsgid \"Digest mutual authentication failure: missing parameters\"\nmsgstr \"\"\n\n#: src/ne_auth.c:1278\n#, c-format\nmsgid \"Digest mutual authentication failure: client nonce mismatch\"\nmsgstr \"\"\n\n#: src/ne_auth.c:1287\n#, c-format\nmsgid \"Digest mutual authentication failure: could not parse nonce count\"\nmsgstr \"\"\n\n#: src/ne_auth.c:1292\n#, c-format\nmsgid \"Digest mutual authentication failure: nonce count mismatch (%u not %u)\"\nmsgstr \"\"\n\n#: src/ne_auth.c:1319\n#, c-format\nmsgid \"Digest mutual authentication failure: request-digest mismatch\"\nmsgstr \"\"\n\n#: src/ne_auth.c:1453\n#, c-format\nmsgid \"ignored %s challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:1550\nmsgid \"could not parse challenge\"\nmsgstr \"\"\n\n#: src/ne_basic.c:98\n#, c-format\nmsgid \"Could not determine file size: %s\"\nmsgstr \"\"\n\n#: src/ne_basic.c:201\n#, c-format\nmsgid \"Response did not include requested range\"\nmsgstr \"\"\n\n#: src/ne_basic.c:236\n#, c-format\nmsgid \"Range is not satisfiable\"\nmsgstr \"\"\n\n#: src/ne_basic.c:241\n#, c-format\nmsgid \"Resource does not support ranged GET requests\"\nmsgstr \"\"\n\n#: src/ne_compress.c:184\n#, c-format\nmsgid \"%s: %s (code %d)\"\nmsgstr \"\"\n\n#: src/ne_compress.c:232\nmsgid \"Could not inflate data\"\nmsgstr \"\"\n\n#: src/ne_compress.c:293\nmsgid \"Could not initialize zlib\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:181\n#, c-format\nmsgid \"[unprintable:#%lu]\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:209\nmsgid \"[unprintable]\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:633\n#, c-format\nmsgid \"Failed to import private key: %s\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:920\nmsgid \"signed using insecure algorithm\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:923\n#, c-format\nmsgid \"unrecognized errors (%u)\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:965 src/ne_openssl.c:496\nmsgid \"Server certificate was missing commonName attribute in subject name\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:979\n#, c-format\nmsgid \"Could not verify server certificate: %s\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:998 src/ne_openssl.c:487\n#, c-format\nmsgid \"Certificate verification error: %s\"\nmsgstr \"\"\n\n#: src/ne_locks.c:640\nmsgid \"LOCK response missing Lock-Token header\"\nmsgstr \"\"\n\n#: src/ne_locks.c:815\n#, c-format\nmsgid \"Response missing activelock for %s\"\nmsgstr \"\"\n\n#: src/ne_locks.c:860\n#, c-format\nmsgid \"No activelock for <%s> returned in LOCK refresh response\"\nmsgstr \"\"\n\n#: src/ne_props.c:364 src/ne_props.c:428\nmsgid \"Response exceeds maximum property count\"\nmsgstr \"\"\n\n#: src/ne_request.c:210\n#, c-format\nmsgid \"%s: connection was closed by proxy server\"\nmsgstr \"\"\n\n#: src/ne_request.c:213\n#, c-format\nmsgid \"%s: connection was closed by server\"\nmsgstr \"\"\n\n#: src/ne_request.c:218\n#, c-format\nmsgid \"%s: connection timed out\"\nmsgstr \"\"\n\n#: src/ne_request.c:321\n#, c-format\nmsgid \"Premature EOF in request body file\"\nmsgstr \"\"\n\n#: src/ne_request.c:328\n#, c-format\nmsgid \"Failed reading request body file: %s\"\nmsgstr \"\"\n\n#: src/ne_request.c:348\nmsgid \"offset invalid\"\nmsgstr \"\"\n\n#: src/ne_request.c:353\n#, c-format\nmsgid \"Could not seek to offset %s of request body file: %s\"\nmsgstr \"\"\n\n#: src/ne_request.c:439\nmsgid \"Could not send request body\"\nmsgstr \"\"\n\n#: src/ne_request.c:466\nmsgid \"Could not send chunked request terminator\"\nmsgstr \"\"\n\n#: src/ne_request.c:842\n#, c-format\nmsgid \"Could not parse redirect destination URL\"\nmsgstr \"\"\n\n#: src/ne_request.c:848\n#, c-format\nmsgid \"Could not parse request target URI\"\nmsgstr \"\"\n\n#: src/ne_request.c:1024\nmsgid \"Could not read chunk size\"\nmsgstr \"\"\n\n#: src/ne_request.c:1027\nmsgid \"Invalid chunk-size line\"\nmsgstr \"\"\n\n#: src/ne_request.c:1045\nmsgid \"Could not parse chunk size\"\nmsgstr \"\"\n\n#: src/ne_request.c:1085\nmsgid \"Could not read response body\"\nmsgstr \"\"\n\n#: src/ne_request.c:1101\nmsgid \"Could not read chunk delimiter\"\nmsgstr \"\"\n\n#: src/ne_request.c:1104\nmsgid \"Chunk delimiter was invalid\"\nmsgstr \"\"\n\n#: src/ne_request.c:1202\nmsgid \"Could not read status line\"\nmsgstr \"\"\n\n#: src/ne_request.c:1224\nmsgid \"Could not parse response status line\"\nmsgstr \"\"\n\n#: src/ne_request.c:1227\nmsgid \"Incompatible HTTP version\"\nmsgstr \"\"\n\n#: src/ne_request.c:1266\nmsgid \"Could not send request\"\nmsgstr \"\"\n\n#: src/ne_request.c:1308\nmsgid \"Timed out reading interim responses\"\nmsgstr \"\"\n\n#: src/ne_request.c:1337 src/ne_request.c:1354 src/ne_request.c:1364\nmsgid \"Error reading response headers\"\nmsgstr \"\"\n\n#: src/ne_request.c:1374\n#, c-format\nmsgid \"Response header too long\"\nmsgstr \"\"\n\n#: src/ne_request.c:1507\nmsgid \"Response exceeded maximum number of header fields\"\nmsgstr \"\"\n\n#: src/ne_request.c:1522\n#, c-format\nmsgid \"Could not resolve hostname `%s': %s\"\nmsgstr \"\"\n\n#: src/ne_request.c:1645\nmsgid \"Unknown transfer-coding in response\"\nmsgstr \"\"\n\n#: src/ne_request.c:1660\nmsgid \"Invalid Content-Length in response\"\nmsgstr \"\"\n\n#: src/ne_request.c:1734\n#, c-format\nmsgid \"Could not write to file: %s\"\nmsgstr \"\"\n\n#: src/ne_request.c:1777\n#, c-format\nmsgid \"Response buffer size too small\"\nmsgstr \"\"\n\n#: src/ne_request.c:1845\n#, c-format\nmsgid \"Could not create SSL connection through proxy server: %s\"\nmsgstr \"\"\n\n#: src/ne_request.c:1884\n#, c-format\nmsgid \"Could not create socket\"\nmsgstr \"\"\n\n#: src/ne_request.c:1920\nmsgid \"Could not connect to server\"\nmsgstr \"\"\n\n#: src/ne_request.c:1922\nmsgid \"Could not connect to proxy server\"\nmsgstr \"\"\n\n#: src/ne_request.c:1965\n#, c-format\nmsgid \"Could not find IPv4 address of hostname %s for SOCKS v4 proxy\"\nmsgstr \"\"\n\n#: src/ne_request.c:2023\n#, c-format\nmsgid \"Could not establish connection from SOCKS proxy (%s:%u): %s\"\nmsgstr \"\"\n\n#: src/ne_session.c:236\nmsgid \"Unknown error.\"\nmsgstr \"\"\n\n#: src/ne_session.c:615\n#, c-format\nmsgid \"Could not set minimum/maximum SSL/TLS versions\"\nmsgstr \"\"\n\n#: src/ne_session.c:622\n#, c-format\nmsgid \"SSL/TLS not enabled for the session\"\nmsgstr \"\"\n\n#: src/ne_session.c:653 src/ne_session.c:664\nmsgid \"[invalid date]\"\nmsgstr \"\"\n\n#: src/ne_session.c:686 src/ne_socket.c:747\n#, c-format\nmsgid \"SSL error: %s\"\nmsgstr \"\"\n\n#: src/ne_session.c:712\n#, c-format\nmsgid \"SSL handshake failed: %s\"\nmsgstr \"\"\n\n#: src/ne_session.c:719\n#, c-format\nmsgid \"No server certificate: %s\"\nmsgstr \"\"\n\n#: src/ne_socket.c:527 src/ne_socket.c:680 src/ne_socket.c:834\nmsgid \"Connection closed\"\nmsgstr \"\"\n\n#: src/ne_socket.c:685\nmsgid \"Retry operation\"\nmsgstr \"\"\n\n#: src/ne_socket.c:700 src/ne_socket.c:735 src/ne_socket.c:848\nmsgid \"Secure connection truncated\"\nmsgstr \"\"\n\n#: src/ne_socket.c:705\nmsgid \"Secure connection reset\"\nmsgstr \"\"\n\n#: src/ne_socket.c:710 src/ne_socket.c:718\nmsgid \"Handshake rejected - client certificate was requested\"\nmsgstr \"\"\n\n#: src/ne_socket.c:721\nmsgid \"Handshake failed\"\nmsgstr \"\"\n\n#: src/ne_socket.c:750\n#, c-format\nmsgid \"SSL error code %d/%d/%lu\"\nmsgstr \"\"\n\n#: src/ne_socket.c:839\n#, c-format\nmsgid \"SSL alert received: %s\"\nmsgstr \"\"\n\n#: src/ne_socket.c:860\nmsgid \"SSL socket read failed\"\nmsgstr \"\"\n\n#: src/ne_socket.c:864\nmsgid \" (client certificate was requested)\"\nmsgstr \"\"\n\n#: src/ne_socket.c:868\n#, c-format\nmsgid \"SSL error%s: %s\"\nmsgstr \"\"\n\n#: src/ne_socket.c:994\nmsgid \"Line too long\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1155 src/ne_socket.c:1161\nmsgid \"Host not found\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1404\nmsgid \"Connection timed out\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1603\nmsgid \"Socket descriptor number exceeds FD_SETSIZE\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1665\nmsgid \"Socket family not supported\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1825\nmsgid \"certificate is not yet valid\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1826\nmsgid \"certificate has expired\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1827\nmsgid \"certificate issued for a different hostname\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1828\nmsgid \"issuer is not trusted\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1829\nmsgid \"bad certificate chain\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1830\nmsgid \"certificate has been revoked\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1835\nmsgid \"Server certificate verification failed: \"\nmsgstr \"\"\n\n#: src/ne_socket.c:1913\n#, c-format\nmsgid \"SSL error: failed to set priority string at '%s'\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1968\nmsgid \"Client certificate verification failed\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1990\nmsgid \"SSL disabled due to lack of entropy\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1996\nmsgid \"Could not create SSL structure\"\nmsgstr \"\"\n\n#: src/ne_socket.c:2210\nmsgid \"SSL server did not present certificate\"\nmsgstr \"\"\n\n#: src/ne_socket.c:2240\nmsgid \"Missing flags for socket shutdown\"\nmsgstr \"\"\n\n#: src/ne_socket.c:2258 src/ne_socket.c:2269 src/ne_socket.c:2284\nmsgid \"Incomplete TLS closure\"\nmsgstr \"\"\n\n#: src/ne_socks.c:65\nmsgid \"failure\"\nmsgstr \"\"\n\n#: src/ne_socks.c:68\nmsgid \"connection not permitted\"\nmsgstr \"\"\n\n#: src/ne_socks.c:71\nmsgid \"network unreachable\"\nmsgstr \"\"\n\n#: src/ne_socks.c:74\nmsgid \"host unreachable\"\nmsgstr \"\"\n\n#: src/ne_socks.c:77\nmsgid \"TTL expired\"\nmsgstr \"\"\n\n#: src/ne_socks.c:80\nmsgid \"command not supported\"\nmsgstr \"\"\n\n#: src/ne_socks.c:83\nmsgid \"address type not supported\"\nmsgstr \"\"\n\n#: src/ne_socks.c:86\n#, c-format\nmsgid \"%s: unrecognized error (%u)\"\nmsgstr \"\"\n\n#: src/ne_socks.c:128 src/ne_socks.c:328\nmsgid \"Could not send message to proxy\"\nmsgstr \"\"\n\n#: src/ne_socks.c:133\nmsgid \"Could not read initial response from proxy\"\nmsgstr \"\"\n\n#: src/ne_socks.c:136\nmsgid \"Invalid version in proxy response\"\nmsgstr \"\"\n\n#: src/ne_socks.c:157\nmsgid \"Could not send login message\"\nmsgstr \"\"\n\n#: src/ne_socks.c:162\nmsgid \"Could not read login reply\"\nmsgstr \"\"\n\n#: src/ne_socks.c:165\nmsgid \"Invalid version in login reply\"\nmsgstr \"\"\n\n#: src/ne_socks.c:168\nmsgid \"Authentication failed\"\nmsgstr \"\"\n\n#: src/ne_socks.c:172\nmsgid \"No acceptable authentication method\"\nmsgstr \"\"\n\n#: src/ne_socks.c:174\nmsgid \"Unexpected authentication method chosen\"\nmsgstr \"\"\n\n#: src/ne_socks.c:210\nmsgid \"Could not send connect request\"\nmsgstr \"\"\n\n#: src/ne_socks.c:215\nmsgid \"Could not read connect reply\"\nmsgstr \"\"\n\n#: src/ne_socks.c:218\nmsgid \"Invalid version in connect reply\"\nmsgstr \"\"\n\n#: src/ne_socks.c:221 src/ne_socks.c:337\nmsgid \"Could not connect\"\nmsgstr \"\"\n\n#: src/ne_socks.c:235\nmsgid \"Could not read FQDN length in connect reply\"\nmsgstr \"\"\n\n#: src/ne_socks.c:240\nmsgid \"Unknown address type in connect reply\"\nmsgstr \"\"\n\n#: src/ne_socks.c:245\nmsgid \"Could not read address in connect reply\"\nmsgstr \"\"\n\n#: src/ne_socks.c:266\nmsgid \"request rejected or failed\"\nmsgstr \"\"\n\n#: src/ne_socks.c:269\nmsgid \"could not establish connection to identd\"\nmsgstr \"\"\n\n#: src/ne_socks.c:272\nmsgid \"rejected due to identd user mismatch\"\nmsgstr \"\"\n\n#: src/ne_socks.c:275\n#, c-format\nmsgid \"%s: unrecognized failure (%u)\"\nmsgstr \"\"\n\n#: src/ne_socks.c:333\nmsgid \"Could not read response from proxy\"\nmsgstr \"\"\n\n#: src/ne_xml.c:190\n#, c-format\nmsgid \"XML parse error: %s\"\nmsgstr \"\"\n\n#: src/ne_xml.c:305\n#, c-format\nmsgid \"XML parse error at line %d: invalid element name\"\nmsgstr \"\"\n\n#: src/ne_xml.c:499\nmsgid \"Unknown error\"\nmsgstr \"\"\n\n#: src/ne_xml.c:625\nmsgid \"Invalid Byte Order Mark\"\nmsgstr \"\"\n\n#: src/ne_xml.c:714\n#, c-format\nmsgid \"XML parse error at line %d: %s\"\nmsgstr \"\"\n\n#: src/ne_xmlreq.c:38\n#, c-format\nmsgid \"Could not parse response: %s\"\nmsgstr \"\"\n"
  },
  {
    "path": "po/nn.po",
    "content": "# Norwegian Nynorsk sitecopy translation.\n# Copyright (C) 2001 Karl Ove Hufthammer.\n# Karl Ove Hufthammer <karl@huftis.org>, 2002.\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: sitecopy 0.11.4\\n\"\n\"Report-Msgid-Bugs-To: https://github.com/notroj/neon\\n\"\n\"POT-Creation-Date: 2026-03-15 08:52+0000\\n\"\n\"PO-Revision-Date: 2002-11-07 18:11+0100\\n\"\n\"Last-Translator: Karl Ove Hufthammer <karl@huftis.org>\\n\"\n\"Language-Team: Norwegian Nynorsk <i18n-nn@lister.ping.uio.no>\\n\"\n\"Language: nn\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: src/ne_207.c:231\n#, c-format\nmsgid \"\"\n\"Invalid HTTP status line in status element at line %d of response:\\n\"\n\"Status line was: %s\"\nmsgstr \"\"\n\"Ugyldig HTTP-statuslinje i statuselement på linje %d av svaret:\\n\"\n\"Statuslinja var: %s\"\n\n#: src/ne_auth.c:130\n#, fuzzy, c-format\nmsgid \"Could not authenticate to server: %s\"\nmsgstr \"Klarte ikkje kopla til tenaren.\"\n\n#: src/ne_auth.c:135\n#, fuzzy, c-format\nmsgid \"Could not authenticate to proxy server: %s\"\nmsgstr \"Klarte ikkje kopla til mellomtenar\"\n\n#: src/ne_auth.c:338\n#, c-format\nmsgid \"rejected %s challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:379\nmsgid \"missing realm in Basic challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:393\nmsgid \"cannot handle Basic challenge for username containing colon\"\nmsgstr \"\"\n\n#: src/ne_auth.c:496\nmsgid \"invalid Negotiate token\"\nmsgstr \"\"\n\n#: src/ne_auth.c:519\n#, fuzzy\nmsgid \"GSSAPI authentication error: \"\nmsgstr \"Krev autentisering på %s «%s»:\\n\"\n\n#: src/ne_auth.c:532\n#, c-format\nmsgid \"GSSAPI failure (code %u)\"\nmsgstr \"\"\n\n#: src/ne_auth.c:567\nmsgid \"ignoring empty Negotiate continuation\"\nmsgstr \"\"\n\n#: src/ne_auth.c:582\n#, c-format\nmsgid \"Negotiate response verification failed: invalid response header token\"\nmsgstr \"\"\n\n#: src/ne_auth.c:604\n#, fuzzy, c-format\nmsgid \"Negotiate response verification failure: %s\"\nmsgstr \"Tenarsertifikatet er utgått på dato.\"\n\n#: src/ne_auth.c:668\n#, c-format\nmsgid \"SSPI response verification failed: invalid response header token\"\nmsgstr \"\"\n\n#: src/ne_auth.c:794\nmsgid \"unexpected token in NTLM challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:822\nmsgid \"malformed NTLM challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:840\n#, fuzzy\nmsgid \"could not handle NTLM challenge\"\nmsgstr \"Klarte ikkje tolka storleik på oppdelt svar\"\n\n#: src/ne_auth.c:908\n#, fuzzy\nmsgid \"could not handle non-ASCII username in Digest challenge\"\nmsgstr \"Klarte ikkje tolka storleik på oppdelt svar\"\n\n#: src/ne_auth.c:936\nmsgid \"unknown algorithm in Digest challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:943\nmsgid \"legacy Digest challenge not supported\"\nmsgstr \"\"\n\n#: src/ne_auth.c:947\nmsgid \"incompatible algorithm in Digest challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:951\nmsgid \"missing parameter in Digest challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:955\nmsgid \"initial Digest challenge was stale\"\nmsgstr \"\"\n\n#: src/ne_auth.c:962\nmsgid \"stale Digest challenge with new algorithm or realm\"\nmsgstr \"\"\n\n#: src/ne_auth.c:969\n#, c-format\nmsgid \"%s algorithm in Digest challenge not supported\"\nmsgstr \"\"\n\n#: src/ne_auth.c:985\n#, fuzzy\nmsgid \"could not parse domain in Digest challenge\"\nmsgstr \"Klarte ikkje tolka storleik på oppdelt svar\"\n\n#: src/ne_auth.c:992\n#, fuzzy\nmsgid \"cannot create client nonce for Digest challenge\"\nmsgstr \"Klarte ikkje tolka storleik på oppdelt svar\"\n\n#: src/ne_auth.c:1273\n#, c-format\nmsgid \"Digest mutual authentication failure: missing parameters\"\nmsgstr \"\"\n\n#: src/ne_auth.c:1278\n#, c-format\nmsgid \"Digest mutual authentication failure: client nonce mismatch\"\nmsgstr \"\"\n\n#: src/ne_auth.c:1287\n#, c-format\nmsgid \"Digest mutual authentication failure: could not parse nonce count\"\nmsgstr \"\"\n\n#: src/ne_auth.c:1292\n#, c-format\nmsgid \"Digest mutual authentication failure: nonce count mismatch (%u not %u)\"\nmsgstr \"\"\n\n#: src/ne_auth.c:1319\n#, c-format\nmsgid \"Digest mutual authentication failure: request-digest mismatch\"\nmsgstr \"\"\n\n#: src/ne_auth.c:1453\n#, c-format\nmsgid \"ignored %s challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:1550\n#, fuzzy\nmsgid \"could not parse challenge\"\nmsgstr \"Klarte ikkje tolka storleik på oppdelt svar\"\n\n#: src/ne_basic.c:98\n#, fuzzy, c-format\nmsgid \"Could not determine file size: %s\"\nmsgstr \"Fann ikkje fillengda: %s\"\n\n#: src/ne_basic.c:201\n#, c-format\nmsgid \"Response did not include requested range\"\nmsgstr \"\"\n\n#: src/ne_basic.c:236\n#, fuzzy, c-format\nmsgid \"Range is not satisfiable\"\nmsgstr \"Området finst ikkje.\"\n\n#: src/ne_basic.c:241\n#, fuzzy, c-format\nmsgid \"Resource does not support ranged GET requests\"\nmsgstr \"Tenaren kan ikkje handtera kommandoar for delvis GET.\"\n\n#: src/ne_compress.c:184\n#, c-format\nmsgid \"%s: %s (code %d)\"\nmsgstr \"\"\n\n#: src/ne_compress.c:232\n#, fuzzy\nmsgid \"Could not inflate data\"\nmsgstr \"Klarte ikkje opna fil: \"\n\n#: src/ne_compress.c:293\n#, fuzzy\nmsgid \"Could not initialize zlib\"\nmsgstr \"Klarte ikkje opna fil: \"\n\n#: src/ne_gnutls.c:181\n#, c-format\nmsgid \"[unprintable:#%lu]\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:209\nmsgid \"[unprintable]\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:633\n#, c-format\nmsgid \"Failed to import private key: %s\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:920\nmsgid \"signed using insecure algorithm\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:923\n#, c-format\nmsgid \"unrecognized errors (%u)\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:965 src/ne_openssl.c:496\nmsgid \"Server certificate was missing commonName attribute in subject name\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:979\n#, fuzzy, c-format\nmsgid \"Could not verify server certificate: %s\"\nmsgstr \"Klarte ikkje skriva til fil: %s\"\n\n#: src/ne_gnutls.c:998 src/ne_openssl.c:487\n#, c-format\nmsgid \"Certificate verification error: %s\"\nmsgstr \"\"\n\n#: src/ne_locks.c:640\nmsgid \"LOCK response missing Lock-Token header\"\nmsgstr \"\"\n\n#: src/ne_locks.c:815\n#, c-format\nmsgid \"Response missing activelock for %s\"\nmsgstr \"\"\n\n#: src/ne_locks.c:860\n#, c-format\nmsgid \"No activelock for <%s> returned in LOCK refresh response\"\nmsgstr \"\"\n\n#: src/ne_props.c:364 src/ne_props.c:428\n#, fuzzy\nmsgid \"Response exceeds maximum property count\"\nmsgstr \"Svaret inneheld for mange header-felt.\"\n\n#: src/ne_request.c:210\n#, fuzzy, c-format\nmsgid \"%s: connection was closed by proxy server\"\nmsgstr \"%s: tilkoplinga vart lukka av mellomtenaren.\"\n\n#: src/ne_request.c:213\n#, fuzzy, c-format\nmsgid \"%s: connection was closed by server\"\nmsgstr \"%s: tilkoplinga vart lukka av tenaren.\"\n\n#: src/ne_request.c:218\n#, fuzzy, c-format\nmsgid \"%s: connection timed out\"\nmsgstr \"%s: sambandet vart tidsavbrote.\"\n\n#: src/ne_request.c:321\n#, fuzzy, c-format\nmsgid \"Premature EOF in request body file\"\nmsgstr \"Klarte ikkje skriva til fil: %s\"\n\n#: src/ne_request.c:328\n#, fuzzy, c-format\nmsgid \"Failed reading request body file: %s\"\nmsgstr \"Klarte ikkje skriva til fil: %s\"\n\n#: src/ne_request.c:348\nmsgid \"offset invalid\"\nmsgstr \"\"\n\n#: src/ne_request.c:353\n#, fuzzy, c-format\nmsgid \"Could not seek to offset %s of request body file: %s\"\nmsgstr \"Klarte ikkje skriva til fil: %s\"\n\n#: src/ne_request.c:439\nmsgid \"Could not send request body\"\nmsgstr \"Klarte ikkje senda førespurnad\"\n\n#: src/ne_request.c:466\n#, fuzzy\nmsgid \"Could not send chunked request terminator\"\nmsgstr \"Klarte ikkje senda førespurnad\"\n\n#: src/ne_request.c:842\n#, fuzzy, c-format\nmsgid \"Could not parse redirect destination URL\"\nmsgstr \"Klarte ikkje tolka vidaresendingsadresse.\"\n\n#: src/ne_request.c:848\n#, fuzzy, c-format\nmsgid \"Could not parse request target URI\"\nmsgstr \"Klarte ikkje tolka vidaresendingsadresse.\"\n\n#: src/ne_request.c:1024\nmsgid \"Could not read chunk size\"\nmsgstr \"Klarte ikkje lesa storleik på oppdelt svar\"\n\n#: src/ne_request.c:1027\nmsgid \"Invalid chunk-size line\"\nmsgstr \"\"\n\n#: src/ne_request.c:1045\nmsgid \"Could not parse chunk size\"\nmsgstr \"Klarte ikkje tolka storleik på oppdelt svar\"\n\n#: src/ne_request.c:1085\nmsgid \"Could not read response body\"\nmsgstr \"Klarte ikkje lesa svar\"\n\n#: src/ne_request.c:1101\n#, fuzzy\nmsgid \"Could not read chunk delimiter\"\nmsgstr \"Klarte ikkje lesa storleik på oppdelt svar\"\n\n#: src/ne_request.c:1104\nmsgid \"Chunk delimiter was invalid\"\nmsgstr \"\"\n\n#: src/ne_request.c:1202\nmsgid \"Could not read status line\"\nmsgstr \"Klarte ikkje lesa statuslinja\"\n\n#: src/ne_request.c:1224\n#, fuzzy\nmsgid \"Could not parse response status line\"\nmsgstr \"Klarte ikkje tolka statuslinja i svaret.\"\n\n#: src/ne_request.c:1227\nmsgid \"Incompatible HTTP version\"\nmsgstr \"\"\n\n#: src/ne_request.c:1266\nmsgid \"Could not send request\"\nmsgstr \"Klarte ikkje senda førespurnad\"\n\n#: src/ne_request.c:1308\n#, fuzzy\nmsgid \"Timed out reading interim responses\"\nmsgstr \"Klarte ikkje lesa svarlinje\"\n\n#: src/ne_request.c:1337 src/ne_request.c:1354 src/ne_request.c:1364\nmsgid \"Error reading response headers\"\nmsgstr \"Feil ved lesing av svarhovud\"\n\n#: src/ne_request.c:1374\n#, c-format\nmsgid \"Response header too long\"\nmsgstr \"For langt svarhovud\"\n\n#: src/ne_request.c:1507\n#, fuzzy\nmsgid \"Response exceeded maximum number of header fields\"\nmsgstr \"Svaret inneheld for mange header-felt.\"\n\n#: src/ne_request.c:1522\n#, fuzzy, c-format\nmsgid \"Could not resolve hostname `%s': %s\"\nmsgstr \"%s: Feil: Fann ikkje adressa til nettverksvert (%s).\\n\"\n\n#: src/ne_request.c:1645\nmsgid \"Unknown transfer-coding in response\"\nmsgstr \"\"\n\n#: src/ne_request.c:1660\nmsgid \"Invalid Content-Length in response\"\nmsgstr \"\"\n\n#: src/ne_request.c:1734\n#, c-format\nmsgid \"Could not write to file: %s\"\nmsgstr \"Klarte ikkje skriva til fil: %s\"\n\n#: src/ne_request.c:1777\n#, fuzzy, c-format\nmsgid \"Response buffer size too small\"\nmsgstr \"For langt svarhovud\"\n\n#: src/ne_request.c:1845\n#, fuzzy, c-format\nmsgid \"Could not create SSL connection through proxy server: %s\"\nmsgstr \"Klarte ikkje oppretta SSL-tilkopling til mellomtenar\"\n\n#: src/ne_request.c:1884\n#, fuzzy, c-format\nmsgid \"Could not create socket\"\nmsgstr \"Klarte ikkje forhandla SSL-økt\"\n\n#: src/ne_request.c:1920\nmsgid \"Could not connect to server\"\nmsgstr \"Klarte ikkje kopla til tenaren.\"\n\n#: src/ne_request.c:1922\nmsgid \"Could not connect to proxy server\"\nmsgstr \"Klarte ikkje kopla til mellomtenar\"\n\n#: src/ne_request.c:1965\n#, c-format\nmsgid \"Could not find IPv4 address of hostname %s for SOCKS v4 proxy\"\nmsgstr \"\"\n\n#: src/ne_request.c:2023\n#, fuzzy, c-format\nmsgid \"Could not establish connection from SOCKS proxy (%s:%u): %s\"\nmsgstr \"Klarte ikkje oppretta SSL-tilkopling til mellomtenar\"\n\n#: src/ne_session.c:236\n#, fuzzy\nmsgid \"Unknown error.\"\nmsgstr \"Ukjend systemfeil\"\n\n#: src/ne_session.c:615\n#, c-format\nmsgid \"Could not set minimum/maximum SSL/TLS versions\"\nmsgstr \"\"\n\n#: src/ne_session.c:622\n#, c-format\nmsgid \"SSL/TLS not enabled for the session\"\nmsgstr \"\"\n\n#: src/ne_session.c:653 src/ne_session.c:664\n#, fuzzy\nmsgid \"[invalid date]\"\nmsgstr \"[ugyldig dato]\"\n\n#: src/ne_session.c:686 src/ne_socket.c:747\n#, fuzzy, c-format\nmsgid \"SSL error: %s\"\nmsgstr \"%s: Feil: %s\\n\"\n\n#: src/ne_session.c:712\n#, fuzzy, c-format\nmsgid \"SSL handshake failed: %s\"\nmsgstr \"Klarte ikkje skriva til fil: %s\"\n\n#: src/ne_session.c:719\n#, fuzzy, c-format\nmsgid \"No server certificate: %s\"\nmsgstr \"Klarte ikkje skriva til fil: %s\"\n\n#: src/ne_socket.c:527 src/ne_socket.c:680 src/ne_socket.c:834\n#, fuzzy\nmsgid \"Connection closed\"\nmsgstr \"Tilkoplinga vart lukka av tenaren\"\n\n#: src/ne_socket.c:685\nmsgid \"Retry operation\"\nmsgstr \"\"\n\n#: src/ne_socket.c:700 src/ne_socket.c:735 src/ne_socket.c:848\n#, fuzzy\nmsgid \"Secure connection truncated\"\nmsgstr \"Sambandet vart tidsavbrote.\"\n\n#: src/ne_socket.c:705\n#, fuzzy\nmsgid \"Secure connection reset\"\nmsgstr \"Sambandet vart tidsavbrote.\"\n\n#: src/ne_socket.c:710 src/ne_socket.c:718\nmsgid \"Handshake rejected - client certificate was requested\"\nmsgstr \"\"\n\n#: src/ne_socket.c:721\n#, fuzzy\nmsgid \"Handshake failed\"\nmsgstr \"Klarte ikkje skriva til fil: %s\"\n\n#: src/ne_socket.c:750\n#, c-format\nmsgid \"SSL error code %d/%d/%lu\"\nmsgstr \"\"\n\n#: src/ne_socket.c:839\n#, fuzzy, c-format\nmsgid \"SSL alert received: %s\"\nmsgstr \"%s: Feil: %s\\n\"\n\n#: src/ne_socket.c:860\nmsgid \"SSL socket read failed\"\nmsgstr \"\"\n\n#: src/ne_socket.c:864\n#, fuzzy\nmsgid \" (client certificate was requested)\"\nmsgstr \"Tenarsertifikatet er utgått på dato.\"\n\n#: src/ne_socket.c:868\n#, fuzzy, c-format\nmsgid \"SSL error%s: %s\"\nmsgstr \"%s: Feil: %s\\n\"\n\n#: src/ne_socket.c:994\nmsgid \"Line too long\"\nmsgstr \"For lang linje\"\n\n#: src/ne_socket.c:1155 src/ne_socket.c:1161\nmsgid \"Host not found\"\nmsgstr \"Fann ikkje vert\"\n\n#: src/ne_socket.c:1404\n#, fuzzy\nmsgid \"Connection timed out\"\nmsgstr \"%s: sambandet vart tidsavbrote.\"\n\n#: src/ne_socket.c:1603\nmsgid \"Socket descriptor number exceeds FD_SETSIZE\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1665\nmsgid \"Socket family not supported\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1825\n#, fuzzy\nmsgid \"certificate is not yet valid\"\nmsgstr \"Sertifikatet er gyldig\"\n\n#: src/ne_socket.c:1826\n#, fuzzy\nmsgid \"certificate has expired\"\nmsgstr \"Tenarsertifikatet er utgått på dato.\"\n\n#: src/ne_socket.c:1827\n#, fuzzy\nmsgid \"certificate issued for a different hostname\"\nmsgstr \"Sertifikatet er utferda av:\"\n\n#: src/ne_socket.c:1828\nmsgid \"issuer is not trusted\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1829\n#, fuzzy\nmsgid \"bad certificate chain\"\nmsgstr \"Tenarsertifikatet er utgått på dato.\"\n\n#: src/ne_socket.c:1830\n#, fuzzy\nmsgid \"certificate has been revoked\"\nmsgstr \"Tenarsertifikatet er utgått på dato.\"\n\n#: src/ne_socket.c:1835\n#, fuzzy\nmsgid \"Server certificate verification failed: \"\nmsgstr \"Tenarsertifikatet er utgått på dato.\"\n\n#: src/ne_socket.c:1913\n#, c-format\nmsgid \"SSL error: failed to set priority string at '%s'\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1968\n#, fuzzy\nmsgid \"Client certificate verification failed\"\nmsgstr \"Tenarsertifikatet er utgått på dato.\"\n\n#: src/ne_socket.c:1990\n#, fuzzy\nmsgid \"SSL disabled due to lack of entropy\"\nmsgstr \"SSL avslått grunna mangel på entropi\"\n\n#: src/ne_socket.c:1996\n#, fuzzy\nmsgid \"Could not create SSL structure\"\nmsgstr \"Klarte ikkje forhandla SSL-økt\"\n\n#: src/ne_socket.c:2210\nmsgid \"SSL server did not present certificate\"\nmsgstr \"\"\n\n#: src/ne_socket.c:2240\nmsgid \"Missing flags for socket shutdown\"\nmsgstr \"\"\n\n#: src/ne_socket.c:2258 src/ne_socket.c:2269 src/ne_socket.c:2284\nmsgid \"Incomplete TLS closure\"\nmsgstr \"\"\n\n#: src/ne_socks.c:65\nmsgid \"failure\"\nmsgstr \"\"\n\n#: src/ne_socks.c:68\n#, fuzzy\nmsgid \"connection not permitted\"\nmsgstr \"%s: sambandet vart tidsavbrote.\"\n\n#: src/ne_socks.c:71\nmsgid \"network unreachable\"\nmsgstr \"\"\n\n#: src/ne_socks.c:74\nmsgid \"host unreachable\"\nmsgstr \"\"\n\n#: src/ne_socks.c:77\nmsgid \"TTL expired\"\nmsgstr \"\"\n\n#: src/ne_socks.c:80\nmsgid \"command not supported\"\nmsgstr \"\"\n\n#: src/ne_socks.c:83\nmsgid \"address type not supported\"\nmsgstr \"\"\n\n#: src/ne_socks.c:86\n#, c-format\nmsgid \"%s: unrecognized error (%u)\"\nmsgstr \"\"\n\n#: src/ne_socks.c:128 src/ne_socks.c:328\n#, fuzzy\nmsgid \"Could not send message to proxy\"\nmsgstr \"Klarte ikkje senda førespurnad\"\n\n#: src/ne_socks.c:133\n#, fuzzy\nmsgid \"Could not read initial response from proxy\"\nmsgstr \"Klarte ikkje lesa svar\"\n\n#: src/ne_socks.c:136\nmsgid \"Invalid version in proxy response\"\nmsgstr \"\"\n\n#: src/ne_socks.c:157\n#, fuzzy\nmsgid \"Could not send login message\"\nmsgstr \"Klarte ikkje senda førespurnad\"\n\n#: src/ne_socks.c:162\n#, fuzzy\nmsgid \"Could not read login reply\"\nmsgstr \"Klarte ikkje lesa statuslinja\"\n\n#: src/ne_socks.c:165\nmsgid \"Invalid version in login reply\"\nmsgstr \"\"\n\n#: src/ne_socks.c:168\n#, fuzzy\nmsgid \"Authentication failed\"\nmsgstr \"Krev autentisering på %s «%s»:\\n\"\n\n#: src/ne_socks.c:172\nmsgid \"No acceptable authentication method\"\nmsgstr \"\"\n\n#: src/ne_socks.c:174\nmsgid \"Unexpected authentication method chosen\"\nmsgstr \"\"\n\n#: src/ne_socks.c:210\n#, fuzzy\nmsgid \"Could not send connect request\"\nmsgstr \"Klarte ikkje senda førespurnad\"\n\n#: src/ne_socks.c:215\n#, fuzzy\nmsgid \"Could not read connect reply\"\nmsgstr \"Klarte ikkje kopla til tenaren.\"\n\n#: src/ne_socks.c:218\nmsgid \"Invalid version in connect reply\"\nmsgstr \"\"\n\n#: src/ne_socks.c:221 src/ne_socks.c:337\n#, fuzzy\nmsgid \"Could not connect\"\nmsgstr \"Klarte ikkje kopla til tenaren.\"\n\n#: src/ne_socks.c:235\nmsgid \"Could not read FQDN length in connect reply\"\nmsgstr \"\"\n\n#: src/ne_socks.c:240\nmsgid \"Unknown address type in connect reply\"\nmsgstr \"\"\n\n#: src/ne_socks.c:245\n#, fuzzy\nmsgid \"Could not read address in connect reply\"\nmsgstr \"Klarte ikkje lesa svar\"\n\n#: src/ne_socks.c:266\nmsgid \"request rejected or failed\"\nmsgstr \"\"\n\n#: src/ne_socks.c:269\n#, fuzzy\nmsgid \"could not establish connection to identd\"\nmsgstr \"Klarte ikkje kopla til tenaren.\"\n\n#: src/ne_socks.c:272\nmsgid \"rejected due to identd user mismatch\"\nmsgstr \"\"\n\n#: src/ne_socks.c:275\n#, c-format\nmsgid \"%s: unrecognized failure (%u)\"\nmsgstr \"\"\n\n#: src/ne_socks.c:333\n#, fuzzy\nmsgid \"Could not read response from proxy\"\nmsgstr \"Klarte ikkje lesa svar\"\n\n#: src/ne_xml.c:190\n#, fuzzy, c-format\nmsgid \"XML parse error: %s\"\nmsgstr \"XML-tolkingsfeil på linje %d: %s.\"\n\n#: src/ne_xml.c:305\n#, fuzzy, c-format\nmsgid \"XML parse error at line %d: invalid element name\"\nmsgstr \"XML-tolkingsfeil på linje %d: %s.\"\n\n#: src/ne_xml.c:499\n#, fuzzy\nmsgid \"Unknown error\"\nmsgstr \"Ukjend systemfeil\"\n\n#: src/ne_xml.c:625\nmsgid \"Invalid Byte Order Mark\"\nmsgstr \"\"\n\n#: src/ne_xml.c:714\n#, fuzzy, c-format\nmsgid \"XML parse error at line %d: %s\"\nmsgstr \"XML-tolkingsfeil på linje %d: %s.\"\n\n#: src/ne_xmlreq.c:38\n#, fuzzy, c-format\nmsgid \"Could not parse response: %s\"\nmsgstr \"Klarte ikkje lesa «LIST»-svar.\"\n\n#, fuzzy, c-format\n#~ msgid \"%s hash failed for Digest challenge\"\n#~ msgstr \"Klarte ikkje tolka storleik på oppdelt svar\"\n\n#, fuzzy\n#~ msgid \"Could not read interim response headers\"\n#~ msgstr \"Klarte ikkje lesa svarlinje\"\n\n#, fuzzy\n#~ msgid \"Server certificate changed: connection intercepted?\"\n#~ msgstr \"Tenarsertifikatet er utgått på dato.\"\n\n#, fuzzy\n#~ msgid \"SSL disabled due to library version mismatch\"\n#~ msgstr \"SSL avslått grunna mangel på entropi\"\n\n#, fuzzy\n#~ msgid \"%s: %s\"\n#~ msgstr \"%s: %s\\n\"\n\n#~ msgid \"Server was not authenticated correctly.\"\n#~ msgstr \"Tenaren vart ikkje rett autentisert.\"\n\n#~ msgid \"Proxy server was not authenticated correctly.\"\n#~ msgstr \"Mellomtenaren vart ikkje rett autentisert.\"\n"
  },
  {
    "path": "po/pl.po",
    "content": "# The Polish translation for Neon.\n# Copyright (C) 2007-2009 Arfrever Frehtes Taifersar Arahesis\n# This file is distributed under the same license as the Neon package.\n# Arfrever Frehtes Taifersar Arahesis <Arfrever.FTA@gmail.com>, 2007-2009.\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: Neon 0.30.0\\n\"\n\"Report-Msgid-Bugs-To: https://github.com/notroj/neon\\n\"\n\"POT-Creation-Date: 2026-03-15 08:52+0000\\n\"\n\"PO-Revision-Date: 2009-09-04 02:00+0200\\n\"\n\"Last-Translator: Arfrever Frehtes Taifersar Arahesis \"\n\"<Arfrever.FTA@gmail.com>\\n\"\n\"Language-Team: Polish Neon Translator Arfrever Frehtes Taifersar Arahesis \"\n\"<Arfrever.FTA@gmail.com>\\n\"\n\"Language: \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: src/ne_207.c:231\n#, c-format\nmsgid \"\"\n\"Invalid HTTP status line in status element at line %d of response:\\n\"\n\"Status line was: %s\"\nmsgstr \"\"\n\"Niewłaściwa linia statusu HTTP w elemencie statusu w linii %d odpowiedzi:\\n\"\n\"Linia statusu była: %s\"\n\n#: src/ne_auth.c:130\n#, c-format\nmsgid \"Could not authenticate to server: %s\"\nmsgstr \"Nie można autentykować się do serwera: %s\"\n\n#: src/ne_auth.c:135\n#, c-format\nmsgid \"Could not authenticate to proxy server: %s\"\nmsgstr \"Nie można autentykować się do serwera proxy: %s\"\n\n#: src/ne_auth.c:338\n#, c-format\nmsgid \"rejected %s challenge\"\nmsgstr \"odrzucone wezwanie %s\"\n\n#: src/ne_auth.c:379\nmsgid \"missing realm in Basic challenge\"\nmsgstr \"brakująca domena w wezwaniu Basic\"\n\n#: src/ne_auth.c:393\nmsgid \"cannot handle Basic challenge for username containing colon\"\nmsgstr \"\"\n\n#: src/ne_auth.c:496\nmsgid \"invalid Negotiate token\"\nmsgstr \"niewłaściwy żeton Negotiate\"\n\n#: src/ne_auth.c:519\nmsgid \"GSSAPI authentication error: \"\nmsgstr \"Błąd autentykacji GSSAPI: \"\n\n#: src/ne_auth.c:532\n#, c-format\nmsgid \"GSSAPI failure (code %u)\"\nmsgstr \"Porażka GSSAPI (kod %u)\"\n\n#: src/ne_auth.c:567\nmsgid \"ignoring empty Negotiate continuation\"\nmsgstr \"ignorowanie pustej kontynuacji Negotiate\"\n\n#: src/ne_auth.c:582\n#, c-format\nmsgid \"Negotiate response verification failed: invalid response header token\"\nmsgstr \"\"\n\"weryfikacja odpowiedzi Negotiate nie udała się: niewłaściwy żeton nagłówka \"\n\"odpowiedzi\"\n\n#: src/ne_auth.c:604\n#, c-format\nmsgid \"Negotiate response verification failure: %s\"\nmsgstr \"porażka weryfikacji odpowiedzi Negotiate: %s\"\n\n#: src/ne_auth.c:668\n#, fuzzy, c-format\nmsgid \"SSPI response verification failed: invalid response header token\"\nmsgstr \"\"\n\"weryfikacja odpowiedzi Negotiate nie udała się: niewłaściwy żeton nagłówka \"\n\"odpowiedzi\"\n\n#: src/ne_auth.c:794\n#, fuzzy\nmsgid \"unexpected token in NTLM challenge\"\nmsgstr \"odrzucone wezwanie %s\"\n\n#: src/ne_auth.c:822\n#, fuzzy\nmsgid \"malformed NTLM challenge\"\nmsgstr \"wezwanie %s zignorowane\"\n\n#: src/ne_auth.c:840\n#, fuzzy\nmsgid \"could not handle NTLM challenge\"\nmsgstr \"nie można parsować wezwania\"\n\n#: src/ne_auth.c:908\n#, fuzzy\nmsgid \"could not handle non-ASCII username in Digest challenge\"\nmsgstr \"nie można parsować domeny w wezwaniu Digest\"\n\n#: src/ne_auth.c:936\nmsgid \"unknown algorithm in Digest challenge\"\nmsgstr \"nieznany algorytm w wezwaniu Digest\"\n\n#: src/ne_auth.c:943\n#, fuzzy\nmsgid \"legacy Digest challenge not supported\"\nmsgstr \"początkowe wezwanie Digest było nieaktualne\"\n\n#: src/ne_auth.c:947\nmsgid \"incompatible algorithm in Digest challenge\"\nmsgstr \"niekompatybilny algorytm w wezwaniu Digest\"\n\n#: src/ne_auth.c:951\nmsgid \"missing parameter in Digest challenge\"\nmsgstr \"brakujący parametr w wezwaniu Digest\"\n\n#: src/ne_auth.c:955\nmsgid \"initial Digest challenge was stale\"\nmsgstr \"początkowe wezwanie Digest było nieaktualne\"\n\n#: src/ne_auth.c:962\nmsgid \"stale Digest challenge with new algorithm or realm\"\nmsgstr \"nieaktualne wezwanie Digest z nowym algorytmem lub domeną\"\n\n#: src/ne_auth.c:969\n#, fuzzy, c-format\nmsgid \"%s algorithm in Digest challenge not supported\"\nmsgstr \"nieznany algorytm w wezwaniu Digest\"\n\n#: src/ne_auth.c:985\nmsgid \"could not parse domain in Digest challenge\"\nmsgstr \"nie można parsować domeny w wezwaniu Digest\"\n\n#: src/ne_auth.c:992\n#, fuzzy\nmsgid \"cannot create client nonce for Digest challenge\"\nmsgstr \"nie można parsować domeny w wezwaniu Digest\"\n\n#: src/ne_auth.c:1273\n#, c-format\nmsgid \"Digest mutual authentication failure: missing parameters\"\nmsgstr \"Porażka wzajemnego uwierzytelniania Digest: brakujące parametry\"\n\n#: src/ne_auth.c:1278\n#, c-format\nmsgid \"Digest mutual authentication failure: client nonce mismatch\"\nmsgstr \"\"\n\"Porażka wzajemnego uwierzytelniania Digest: niezgodność posłańca klienta\"\n\n#: src/ne_auth.c:1287\n#, c-format\nmsgid \"Digest mutual authentication failure: could not parse nonce count\"\nmsgstr \"\"\n\"Porażka wzajemnego uwierzytelniania Digest: nie można parsować licznika \"\n\"posłańca\"\n\n#: src/ne_auth.c:1292\n#, c-format\nmsgid \"Digest mutual authentication failure: nonce count mismatch (%u not %u)\"\nmsgstr \"\"\n\"Porażka wzajemnego uwierzytelniania Digest: niezgodność licznika posłańca \"\n\"(%u nie %u)\"\n\n#: src/ne_auth.c:1319\n#, c-format\nmsgid \"Digest mutual authentication failure: request-digest mismatch\"\nmsgstr \"\"\n\"Porażka wzajemnego uwierzytelniania Digest: niezgodność request-digest \"\n\"mismatch\"\n\n#: src/ne_auth.c:1453\n#, c-format\nmsgid \"ignored %s challenge\"\nmsgstr \"wezwanie %s zignorowane\"\n\n#: src/ne_auth.c:1550\nmsgid \"could not parse challenge\"\nmsgstr \"nie można parsować wezwania\"\n\n#: src/ne_basic.c:98\n#, c-format\nmsgid \"Could not determine file size: %s\"\nmsgstr \"Nie można określić rozmiaru pliku: %s\"\n\n#: src/ne_basic.c:201\n#, c-format\nmsgid \"Response did not include requested range\"\nmsgstr \"Odpowiedź nie zawierała wymaganego zakresu\"\n\n#: src/ne_basic.c:236\n#, c-format\nmsgid \"Range is not satisfiable\"\nmsgstr \"Zakres nie może być usatysfakcjonowany\"\n\n#: src/ne_basic.c:241\n#, c-format\nmsgid \"Resource does not support ranged GET requests\"\nmsgstr \"Zasób nie obsługuje zakresowych żądań GET\"\n\n#: src/ne_compress.c:184\n#, c-format\nmsgid \"%s: %s (code %d)\"\nmsgstr \"%s: %s (kod %d)\"\n\n#: src/ne_compress.c:232\nmsgid \"Could not inflate data\"\nmsgstr \"Nie można \"\n\n#: src/ne_compress.c:293\nmsgid \"Could not initialize zlib\"\nmsgstr \"Nie można zainicjalizować zlib\"\n\n#: src/ne_gnutls.c:181\n#, c-format\nmsgid \"[unprintable:#%lu]\"\nmsgstr \"[niedrukowalne:#%lu]\"\n\n#: src/ne_gnutls.c:209\nmsgid \"[unprintable]\"\nmsgstr \"[niedrukowalne]\"\n\n#: src/ne_gnutls.c:633\n#, c-format\nmsgid \"Failed to import private key: %s\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:920\nmsgid \"signed using insecure algorithm\"\nmsgstr \"podpisane przy użyciu niebezpiecznego algorytmu\"\n\n#: src/ne_gnutls.c:923\n#, c-format\nmsgid \"unrecognized errors (%u)\"\nmsgstr \"nierozpoznane błędy (%u)\"\n\n#: src/ne_gnutls.c:965 src/ne_openssl.c:496\nmsgid \"Server certificate was missing commonName attribute in subject name\"\nmsgstr \"Certyfikat serwera nie posiada atrybutu commonName w nazwie tematu\"\n\n#: src/ne_gnutls.c:979\n#, c-format\nmsgid \"Could not verify server certificate: %s\"\nmsgstr \"Nie można zweryfikować certyfikatu serwera: %s\"\n\n#: src/ne_gnutls.c:998 src/ne_openssl.c:487\n#, c-format\nmsgid \"Certificate verification error: %s\"\nmsgstr \"Błąd weryfikacji certyfikatu: %s\"\n\n#: src/ne_locks.c:640\nmsgid \"LOCK response missing Lock-Token header\"\nmsgstr \"Odpowiedź LOCK nie zawiera nagłówka Lock-Token\"\n\n#: src/ne_locks.c:815\n#, c-format\nmsgid \"Response missing activelock for %s\"\nmsgstr \"Odpowiedź nie zawiera aktywnej blokady dla %s\"\n\n#: src/ne_locks.c:860\n#, c-format\nmsgid \"No activelock for <%s> returned in LOCK refresh response\"\nmsgstr \"\"\n\"Nie zwrócono żadnej aktywnej blokady dla <%s> w odpowiedzi LOCK refresh\"\n\n#: src/ne_props.c:364 src/ne_props.c:428\nmsgid \"Response exceeds maximum property count\"\nmsgstr \"Odpowiedź przekracza maksymalną liczbę właściwości\"\n\n#: src/ne_request.c:210\n#, c-format\nmsgid \"%s: connection was closed by proxy server\"\nmsgstr \"%s: połączenie zostało zamknięte przez serwer proxy\"\n\n#: src/ne_request.c:213\n#, c-format\nmsgid \"%s: connection was closed by server\"\nmsgstr \"%s: połączenie zostało zamknięte przez serwer\"\n\n#: src/ne_request.c:218\n#, c-format\nmsgid \"%s: connection timed out\"\nmsgstr \"%s: czas połączenia się skończył\"\n\n#: src/ne_request.c:321\n#, c-format\nmsgid \"Premature EOF in request body file\"\nmsgstr \"\"\n\n#: src/ne_request.c:328\n#, c-format\nmsgid \"Failed reading request body file: %s\"\nmsgstr \"\"\n\n#: src/ne_request.c:348\nmsgid \"offset invalid\"\nmsgstr \"nieprawidłowe przesunięcie\"\n\n#: src/ne_request.c:353\n#, c-format\nmsgid \"Could not seek to offset %s of request body file: %s\"\nmsgstr \"Nie można szukać przesunięcia %s pliku ciała żądania: %s\"\n\n#: src/ne_request.c:439\nmsgid \"Could not send request body\"\nmsgstr \"Nie można wysłać ciała żądania\"\n\n#: src/ne_request.c:466\n#, fuzzy\nmsgid \"Could not send chunked request terminator\"\nmsgstr \"Nie można wysłać żądania połączenia\"\n\n#: src/ne_request.c:842\n#, c-format\nmsgid \"Could not parse redirect destination URL\"\nmsgstr \"Nie można parsować URL-u przeadresowanego celu\"\n\n#: src/ne_request.c:848\n#, fuzzy, c-format\nmsgid \"Could not parse request target URI\"\nmsgstr \"Nie można parsować URL-u przeadresowanego celu\"\n\n#: src/ne_request.c:1024\nmsgid \"Could not read chunk size\"\nmsgstr \"Nie można odczytać rozmiaru kawałka\"\n\n#: src/ne_request.c:1027\nmsgid \"Invalid chunk-size line\"\nmsgstr \"\"\n\n#: src/ne_request.c:1045\nmsgid \"Could not parse chunk size\"\nmsgstr \"Nie można parsować rozmiaru kawałka\"\n\n#: src/ne_request.c:1085\nmsgid \"Could not read response body\"\nmsgstr \"Nie można odczytać ciała odpowiedzi\"\n\n#: src/ne_request.c:1101\nmsgid \"Could not read chunk delimiter\"\nmsgstr \"Nie można odczytać ogranicznika kawałka\"\n\n#: src/ne_request.c:1104\nmsgid \"Chunk delimiter was invalid\"\nmsgstr \"Ogranicznik kawałka był nieprawidłowy\"\n\n#: src/ne_request.c:1202\nmsgid \"Could not read status line\"\nmsgstr \"Nie można odczytać linii statusu\"\n\n#: src/ne_request.c:1224\nmsgid \"Could not parse response status line\"\nmsgstr \"Nie można parsować linii statusu odpowiedzi\"\n\n#: src/ne_request.c:1227\nmsgid \"Incompatible HTTP version\"\nmsgstr \"\"\n\n#: src/ne_request.c:1266\nmsgid \"Could not send request\"\nmsgstr \"Nie można wysłać żądania\"\n\n#: src/ne_request.c:1308\n#, fuzzy\nmsgid \"Timed out reading interim responses\"\nmsgstr \"Nie można odczytać nagłówków tymczasowej odpowiedzi\"\n\n#: src/ne_request.c:1337 src/ne_request.c:1354 src/ne_request.c:1364\nmsgid \"Error reading response headers\"\nmsgstr \"Błąd podczas odczytywania nagłówków odpowiedzi\"\n\n#: src/ne_request.c:1374\n#, c-format\nmsgid \"Response header too long\"\nmsgstr \"Nagłówek odpowiedzi zbyt długi\"\n\n#: src/ne_request.c:1507\nmsgid \"Response exceeded maximum number of header fields\"\nmsgstr \"Odpowiedź przekroczyła maksymalną liczbę pól nagłówka\"\n\n#: src/ne_request.c:1522\n#, c-format\nmsgid \"Could not resolve hostname `%s': %s\"\nmsgstr \"Nie można rozwiązać nazwy hosta `%s': %s\"\n\n#: src/ne_request.c:1645\nmsgid \"Unknown transfer-coding in response\"\nmsgstr \"Nieznane transfer-coding w odpowiedzi\"\n\n#: src/ne_request.c:1660\nmsgid \"Invalid Content-Length in response\"\nmsgstr \"Nieprawidłowe Content-Length w odpowiedzi\"\n\n#: src/ne_request.c:1734\n#, c-format\nmsgid \"Could not write to file: %s\"\nmsgstr \"Nie można pisać do pliku: %s\"\n\n#: src/ne_request.c:1777\n#, fuzzy, c-format\nmsgid \"Response buffer size too small\"\nmsgstr \"Nagłówek odpowiedzi zbyt długi\"\n\n#: src/ne_request.c:1845\n#, c-format\nmsgid \"Could not create SSL connection through proxy server: %s\"\nmsgstr \"Nie można utworzyć połączenia SSL przez serwer proxy: %s\"\n\n#: src/ne_request.c:1884\n#, c-format\nmsgid \"Could not create socket\"\nmsgstr \"Nie można utworzyć gniazda\"\n\n#: src/ne_request.c:1920\nmsgid \"Could not connect to server\"\nmsgstr \"Nie można połączyć się z serwerem\"\n\n#: src/ne_request.c:1922\nmsgid \"Could not connect to proxy server\"\nmsgstr \"Nie można połączyć się z serwerem proxy\"\n\n#: src/ne_request.c:1965\n#, c-format\nmsgid \"Could not find IPv4 address of hostname %s for SOCKS v4 proxy\"\nmsgstr \"Nie można znaleźć adresu IPv4 nazwy hosta %s dla proxy SOCKS v4\"\n\n#: src/ne_request.c:2023\n#, c-format\nmsgid \"Could not establish connection from SOCKS proxy (%s:%u): %s\"\nmsgstr \"Nie można nawiązać połączenia z proxy SOCKS (%s:%u): %s\"\n\n#: src/ne_session.c:236\n#, fuzzy\nmsgid \"Unknown error.\"\nmsgstr \"Nieznany błąd\"\n\n#: src/ne_session.c:615\n#, c-format\nmsgid \"Could not set minimum/maximum SSL/TLS versions\"\nmsgstr \"\"\n\n#: src/ne_session.c:622\n#, c-format\nmsgid \"SSL/TLS not enabled for the session\"\nmsgstr \"\"\n\n#: src/ne_session.c:653 src/ne_session.c:664\nmsgid \"[invalid date]\"\nmsgstr \"[nieprawidłowa data]\"\n\n#: src/ne_session.c:686 src/ne_socket.c:747\n#, c-format\nmsgid \"SSL error: %s\"\nmsgstr \"Błąd SSL: %s\"\n\n#: src/ne_session.c:712\n#, c-format\nmsgid \"SSL handshake failed: %s\"\nmsgstr \"Uzgodnienie SSL nie udało się: %s\"\n\n#: src/ne_session.c:719\n#, fuzzy, c-format\nmsgid \"No server certificate: %s\"\nmsgstr \"Nie można zweryfikować certyfikatu serwera: %s\"\n\n#: src/ne_socket.c:527 src/ne_socket.c:680 src/ne_socket.c:834\nmsgid \"Connection closed\"\nmsgstr \"Połączenie zamknięte\"\n\n#: src/ne_socket.c:685\nmsgid \"Retry operation\"\nmsgstr \"\"\n\n#: src/ne_socket.c:700 src/ne_socket.c:735 src/ne_socket.c:848\nmsgid \"Secure connection truncated\"\nmsgstr \"Bezpieczne połączenie obcięte\"\n\n#: src/ne_socket.c:705\n#, fuzzy\nmsgid \"Secure connection reset\"\nmsgstr \"Bezpieczne połączenie obcięte\"\n\n#: src/ne_socket.c:710 src/ne_socket.c:718\n#, fuzzy\nmsgid \"Handshake rejected - client certificate was requested\"\nmsgstr \"Uzgodnienie SSL nie udało się, certyfikat klienta został zażądany: %s\"\n\n#: src/ne_socket.c:721\n#, fuzzy\nmsgid \"Handshake failed\"\nmsgstr \"Uzgodnienie SSL nie udało się: %s\"\n\n#: src/ne_socket.c:750\n#, c-format\nmsgid \"SSL error code %d/%d/%lu\"\nmsgstr \"Kod błędu SSL %d/%d/%lu\"\n\n#: src/ne_socket.c:839\n#, c-format\nmsgid \"SSL alert received: %s\"\nmsgstr \"Alarm SSL otrzymany: %s\"\n\n#: src/ne_socket.c:860\nmsgid \"SSL socket read failed\"\nmsgstr \"Odczytywanie gniazda SSL nie powiodło się\"\n\n#: src/ne_socket.c:864\n#, fuzzy\nmsgid \" (client certificate was requested)\"\nmsgstr \"Uzgodnienie SSL nie udało się, certyfikat klienta został zażądany: %s\"\n\n#: src/ne_socket.c:868\n#, fuzzy, c-format\nmsgid \"SSL error%s: %s\"\nmsgstr \"Błąd SSL: %s\"\n\n#: src/ne_socket.c:994\nmsgid \"Line too long\"\nmsgstr \"Linia zbyt długa\"\n\n#: src/ne_socket.c:1155 src/ne_socket.c:1161\nmsgid \"Host not found\"\nmsgstr \"Host nieznaleziony\"\n\n#: src/ne_socket.c:1404\nmsgid \"Connection timed out\"\nmsgstr \"Czas połączenia się skończył\"\n\n#: src/ne_socket.c:1603\nmsgid \"Socket descriptor number exceeds FD_SETSIZE\"\nmsgstr \"Numer deskryptoru gniazda przekracza FD_SETSIZE\"\n\n#: src/ne_socket.c:1665\nmsgid \"Socket family not supported\"\nmsgstr \"Rodzina gniazda niewspierana\"\n\n#: src/ne_socket.c:1825\nmsgid \"certificate is not yet valid\"\nmsgstr \"certyfikat nie jest jeszcze poprawny\"\n\n#: src/ne_socket.c:1826\nmsgid \"certificate has expired\"\nmsgstr \"certyfikat wygasł\"\n\n#: src/ne_socket.c:1827\nmsgid \"certificate issued for a different hostname\"\nmsgstr \"certyfikat wydany dla innej nazwy hosta\"\n\n#: src/ne_socket.c:1828\nmsgid \"issuer is not trusted\"\nmsgstr \"wydawca nie jest zaufany\"\n\n#: src/ne_socket.c:1829\nmsgid \"bad certificate chain\"\nmsgstr \"zły łańcuch certyfikatu\"\n\n#: src/ne_socket.c:1830\nmsgid \"certificate has been revoked\"\nmsgstr \"certyfikat został unieważniony\"\n\n#: src/ne_socket.c:1835\nmsgid \"Server certificate verification failed: \"\nmsgstr \"Weryfikacja certyfikatu serwera nie powiodła się: \"\n\n#: src/ne_socket.c:1913\n#, c-format\nmsgid \"SSL error: failed to set priority string at '%s'\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1968\nmsgid \"Client certificate verification failed\"\nmsgstr \"Weryfikacja certyfikatu klienta nie powiodła się\"\n\n#: src/ne_socket.c:1990\nmsgid \"SSL disabled due to lack of entropy\"\nmsgstr \"SSL wyłączone z powodu braku entropii\"\n\n#: src/ne_socket.c:1996\nmsgid \"Could not create SSL structure\"\nmsgstr \"Nie można utworzyć struktury SSL\"\n\n#: src/ne_socket.c:2210\nmsgid \"SSL server did not present certificate\"\nmsgstr \"Serwer SSL nie przedstawił certyfikatu\"\n\n#: src/ne_socket.c:2240\nmsgid \"Missing flags for socket shutdown\"\nmsgstr \"\"\n\n#: src/ne_socket.c:2258 src/ne_socket.c:2269 src/ne_socket.c:2284\nmsgid \"Incomplete TLS closure\"\nmsgstr \"\"\n\n#: src/ne_socks.c:65\nmsgid \"failure\"\nmsgstr \"porażka\"\n\n#: src/ne_socks.c:68\nmsgid \"connection not permitted\"\nmsgstr \"połączenie niedozwolone\"\n\n#: src/ne_socks.c:71\nmsgid \"network unreachable\"\nmsgstr \"sieć nieosiągalna\"\n\n#: src/ne_socks.c:74\nmsgid \"host unreachable\"\nmsgstr \"host nieosiągalny\"\n\n#: src/ne_socks.c:77\nmsgid \"TTL expired\"\nmsgstr \"TTL utraciło ważność\"\n\n#: src/ne_socks.c:80\nmsgid \"command not supported\"\nmsgstr \"polecenie niewspierane\"\n\n#: src/ne_socks.c:83\nmsgid \"address type not supported\"\nmsgstr \"typ adresu niewspierany\"\n\n#: src/ne_socks.c:86\n#, c-format\nmsgid \"%s: unrecognized error (%u)\"\nmsgstr \"%s: nierozpoznany błąd (%u)\"\n\n#: src/ne_socks.c:128 src/ne_socks.c:328\nmsgid \"Could not send message to proxy\"\nmsgstr \"Nie można wysłać wiadomości do proxy\"\n\n#: src/ne_socks.c:133\nmsgid \"Could not read initial response from proxy\"\nmsgstr \"Nie można odczytać początkowej odpowiedzi od proxy\"\n\n#: src/ne_socks.c:136\nmsgid \"Invalid version in proxy response\"\nmsgstr \"Nieprawidłowa wersja w odpowiedzi proxy\"\n\n#: src/ne_socks.c:157\nmsgid \"Could not send login message\"\nmsgstr \"Nie można wysłać wiadomości logowania\"\n\n#: src/ne_socks.c:162\nmsgid \"Could not read login reply\"\nmsgstr \"Nie można odczytać odpowiedzi logowania\"\n\n#: src/ne_socks.c:165\nmsgid \"Invalid version in login reply\"\nmsgstr \"Nieprawidłowa wersja w odpowiedzi logowania\"\n\n#: src/ne_socks.c:168\nmsgid \"Authentication failed\"\nmsgstr \"Błąd uwierzytelniania\"\n\n#: src/ne_socks.c:172\nmsgid \"No acceptable authentication method\"\nmsgstr \"Brak akceptowalnej metody uwierzytelniania\"\n\n#: src/ne_socks.c:174\nmsgid \"Unexpected authentication method chosen\"\nmsgstr \"Nieoczekiwana metoda uwierzytelniania wybrana\"\n\n#: src/ne_socks.c:210\nmsgid \"Could not send connect request\"\nmsgstr \"Nie można wysłać żądania połączenia\"\n\n#: src/ne_socks.c:215\nmsgid \"Could not read connect reply\"\nmsgstr \"Nie można odczytac odpowiedzi połączenia\"\n\n#: src/ne_socks.c:218\nmsgid \"Invalid version in connect reply\"\nmsgstr \"Nieprawidłowa wersja w odpowiedzi połączenia\"\n\n#: src/ne_socks.c:221 src/ne_socks.c:337\nmsgid \"Could not connect\"\nmsgstr \"Nie można połączyć się\"\n\n#: src/ne_socks.c:235\nmsgid \"Could not read FQDN length in connect reply\"\nmsgstr \"Nie można odczytać długości FQDN w odpowiedzi połączenia\"\n\n#: src/ne_socks.c:240\nmsgid \"Unknown address type in connect reply\"\nmsgstr \"Nieznany typ adresu w odpowiedzi połączenia\"\n\n#: src/ne_socks.c:245\nmsgid \"Could not read address in connect reply\"\nmsgstr \"Nie można odczytać adresu w odpowiedzi połączenia\"\n\n#: src/ne_socks.c:266\nmsgid \"request rejected or failed\"\nmsgstr \"żądanie odrzucone lub nieudane\"\n\n#: src/ne_socks.c:269\nmsgid \"could not establish connection to identd\"\nmsgstr \"Nie można połączyć się z identd\"\n\n#: src/ne_socks.c:272\nmsgid \"rejected due to identd user mismatch\"\nmsgstr \"odrzucone z powodu niezgodności użytkownika identd\"\n\n#: src/ne_socks.c:275\n#, c-format\nmsgid \"%s: unrecognized failure (%u)\"\nmsgstr \"%s: nierozpoznana porażka (%u)\"\n\n#: src/ne_socks.c:333\nmsgid \"Could not read response from proxy\"\nmsgstr \"Nie można odczytać odpowiedzi od proxy\"\n\n#: src/ne_xml.c:190\n#, fuzzy, c-format\nmsgid \"XML parse error: %s\"\nmsgstr \"Błąd podczas parsowania XML w linii %d: %s\"\n\n#: src/ne_xml.c:305\n#, c-format\nmsgid \"XML parse error at line %d: invalid element name\"\nmsgstr \"Błąd podczas parsowania XML w linii %d: nieprawidłowa nazwa elementu\"\n\n#: src/ne_xml.c:499\nmsgid \"Unknown error\"\nmsgstr \"Nieznany błąd\"\n\n#: src/ne_xml.c:625\nmsgid \"Invalid Byte Order Mark\"\nmsgstr \"Nieprawidłowy Znacznik Kolejności Bajtów\"\n\n#: src/ne_xml.c:714\n#, c-format\nmsgid \"XML parse error at line %d: %s\"\nmsgstr \"Błąd podczas parsowania XML w linii %d: %s\"\n\n#: src/ne_xmlreq.c:38\n#, c-format\nmsgid \"Could not parse response: %s\"\nmsgstr \"Nie można parsować odpowiedzi: %s\"\n\n#, fuzzy, c-format\n#~ msgid \"%s hash failed for Digest challenge\"\n#~ msgstr \"brakujący parametr w wezwaniu Digest\"\n\n#, c-format\n#~ msgid \"Server did not send certificate chain\"\n#~ msgstr \"Serwer nie wysłał łańcucha certyfikatu\"\n\n#, fuzzy\n#~ msgid \"Could not read status line (TLS client certificate was requested)\"\n#~ msgstr \"\"\n#~ \"Uzgodnienie SSL nie udało się, certyfikat klienta został zażądany: %s\"\n\n#~ msgid \"Could not read interim response headers\"\n#~ msgstr \"Nie można odczytać nagłówków tymczasowej odpowiedzi\"\n\n#~ msgid \"Server certificate changed: connection intercepted?\"\n#~ msgstr \"Certyfikat serwera zmienił się: połączenie przechwycone?\"\n\n#~ msgid \"SSL disabled due to library version mismatch\"\n#~ msgstr \"SSL wyłączone z powodu niezgodności wersji biblioteki\"\n"
  },
  {
    "path": "po/ru.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 1999 Michael Sobolev\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: sitecopy 0.11.5\\n\"\n\"Report-Msgid-Bugs-To: https://github.com/notroj/neon\\n\"\n\"POT-Creation-Date: 2026-03-15 08:52+0000\\n\"\n\"PO-Revision-Date: 2002-11-11 14:28+0000\\n\"\n\"Last-Translator: Michael Sobolev <neon@webdav.org>\\n\"\n\"Language-Team: ru\\n\"\n\"Language: \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=koi8-r\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: src/ne_207.c:231\n#, c-format\nmsgid \"\"\n\"Invalid HTTP status line in status element at line %d of response:\\n\"\n\"Status line was: %s\"\nmsgstr \"\"\n\n#: src/ne_auth.c:130\n#, fuzzy, c-format\nmsgid \"Could not authenticate to server: %s\"\nmsgstr \"%s: :     : %s\\n\"\n\n#: src/ne_auth.c:135\n#, fuzzy, c-format\nmsgid \"Could not authenticate to proxy server: %s\"\nmsgstr \"%s: :     : %s\\n\"\n\n#: src/ne_auth.c:338\n#, c-format\nmsgid \"rejected %s challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:379\nmsgid \"missing realm in Basic challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:393\nmsgid \"cannot handle Basic challenge for username containing colon\"\nmsgstr \"\"\n\n#: src/ne_auth.c:496\nmsgid \"invalid Negotiate token\"\nmsgstr \"\"\n\n#: src/ne_auth.c:519\nmsgid \"GSSAPI authentication error: \"\nmsgstr \"\"\n\n#: src/ne_auth.c:532\n#, c-format\nmsgid \"GSSAPI failure (code %u)\"\nmsgstr \"\"\n\n#: src/ne_auth.c:567\nmsgid \"ignoring empty Negotiate continuation\"\nmsgstr \"\"\n\n#: src/ne_auth.c:582\n#, c-format\nmsgid \"Negotiate response verification failed: invalid response header token\"\nmsgstr \"\"\n\n#: src/ne_auth.c:604\n#, c-format\nmsgid \"Negotiate response verification failure: %s\"\nmsgstr \"\"\n\n#: src/ne_auth.c:668\n#, c-format\nmsgid \"SSPI response verification failed: invalid response header token\"\nmsgstr \"\"\n\n#: src/ne_auth.c:794\nmsgid \"unexpected token in NTLM challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:822\nmsgid \"malformed NTLM challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:840\n#, fuzzy\nmsgid \"could not handle NTLM challenge\"\nmsgstr \"%s: :     : %s\\n\"\n\n#: src/ne_auth.c:908\n#, fuzzy\nmsgid \"could not handle non-ASCII username in Digest challenge\"\nmsgstr \"%s: :     : %s\\n\"\n\n#: src/ne_auth.c:936\nmsgid \"unknown algorithm in Digest challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:943\nmsgid \"legacy Digest challenge not supported\"\nmsgstr \"\"\n\n#: src/ne_auth.c:947\nmsgid \"incompatible algorithm in Digest challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:951\nmsgid \"missing parameter in Digest challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:955\nmsgid \"initial Digest challenge was stale\"\nmsgstr \"\"\n\n#: src/ne_auth.c:962\nmsgid \"stale Digest challenge with new algorithm or realm\"\nmsgstr \"\"\n\n#: src/ne_auth.c:969\n#, c-format\nmsgid \"%s algorithm in Digest challenge not supported\"\nmsgstr \"\"\n\n#: src/ne_auth.c:985\n#, fuzzy\nmsgid \"could not parse domain in Digest challenge\"\nmsgstr \"%s: :     : %s\\n\"\n\n#: src/ne_auth.c:992\n#, fuzzy\nmsgid \"cannot create client nonce for Digest challenge\"\nmsgstr \"%s: :     : %s\\n\"\n\n#: src/ne_auth.c:1273\n#, c-format\nmsgid \"Digest mutual authentication failure: missing parameters\"\nmsgstr \"\"\n\n#: src/ne_auth.c:1278\n#, c-format\nmsgid \"Digest mutual authentication failure: client nonce mismatch\"\nmsgstr \"\"\n\n#: src/ne_auth.c:1287\n#, c-format\nmsgid \"Digest mutual authentication failure: could not parse nonce count\"\nmsgstr \"\"\n\n#: src/ne_auth.c:1292\n#, c-format\nmsgid \"Digest mutual authentication failure: nonce count mismatch (%u not %u)\"\nmsgstr \"\"\n\n#: src/ne_auth.c:1319\n#, c-format\nmsgid \"Digest mutual authentication failure: request-digest mismatch\"\nmsgstr \"\"\n\n#: src/ne_auth.c:1453\n#, c-format\nmsgid \"ignored %s challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:1550\n#, fuzzy\nmsgid \"could not parse challenge\"\nmsgstr \"%s: :     : %s\\n\"\n\n#: src/ne_basic.c:98\n#, fuzzy, c-format\nmsgid \"Could not determine file size: %s\"\nmsgstr \"%s: :     : %s\\n\"\n\n#: src/ne_basic.c:201\n#, c-format\nmsgid \"Response did not include requested range\"\nmsgstr \"\"\n\n#: src/ne_basic.c:236\n#, c-format\nmsgid \"Range is not satisfiable\"\nmsgstr \"\"\n\n#: src/ne_basic.c:241\n#, c-format\nmsgid \"Resource does not support ranged GET requests\"\nmsgstr \"\"\n\n#: src/ne_compress.c:184\n#, c-format\nmsgid \"%s: %s (code %d)\"\nmsgstr \"\"\n\n#: src/ne_compress.c:232\n#, fuzzy\nmsgid \"Could not inflate data\"\nmsgstr \"%s: :     : %s\\n\"\n\n#: src/ne_compress.c:293\n#, fuzzy\nmsgid \"Could not initialize zlib\"\nmsgstr \"%s: :     : %s\\n\"\n\n#: src/ne_gnutls.c:181\n#, c-format\nmsgid \"[unprintable:#%lu]\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:209\nmsgid \"[unprintable]\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:633\n#, c-format\nmsgid \"Failed to import private key: %s\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:920\nmsgid \"signed using insecure algorithm\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:923\n#, c-format\nmsgid \"unrecognized errors (%u)\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:965 src/ne_openssl.c:496\nmsgid \"Server certificate was missing commonName attribute in subject name\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:979\n#, fuzzy, c-format\nmsgid \"Could not verify server certificate: %s\"\nmsgstr \"%s: :     : %s\\n\"\n\n#: src/ne_gnutls.c:998 src/ne_openssl.c:487\n#, c-format\nmsgid \"Certificate verification error: %s\"\nmsgstr \"\"\n\n#: src/ne_locks.c:640\nmsgid \"LOCK response missing Lock-Token header\"\nmsgstr \"\"\n\n#: src/ne_locks.c:815\n#, c-format\nmsgid \"Response missing activelock for %s\"\nmsgstr \"\"\n\n#: src/ne_locks.c:860\n#, c-format\nmsgid \"No activelock for <%s> returned in LOCK refresh response\"\nmsgstr \"\"\n\n#: src/ne_props.c:364 src/ne_props.c:428\nmsgid \"Response exceeds maximum property count\"\nmsgstr \"\"\n\n#: src/ne_request.c:210\n#, c-format\nmsgid \"%s: connection was closed by proxy server\"\nmsgstr \"\"\n\n#: src/ne_request.c:213\n#, c-format\nmsgid \"%s: connection was closed by server\"\nmsgstr \"\"\n\n#: src/ne_request.c:218\n#, c-format\nmsgid \"%s: connection timed out\"\nmsgstr \"\"\n\n#: src/ne_request.c:321\n#, fuzzy, c-format\nmsgid \"Premature EOF in request body file\"\nmsgstr \"%s: :     : %s\\n\"\n\n#: src/ne_request.c:328\n#, fuzzy, c-format\nmsgid \"Failed reading request body file: %s\"\nmsgstr \"%s: :     : %s\\n\"\n\n#: src/ne_request.c:348\nmsgid \"offset invalid\"\nmsgstr \"\"\n\n#: src/ne_request.c:353\n#, fuzzy, c-format\nmsgid \"Could not seek to offset %s of request body file: %s\"\nmsgstr \"%s: :     : %s\\n\"\n\n#: src/ne_request.c:439\nmsgid \"Could not send request body\"\nmsgstr \"\"\n\n#: src/ne_request.c:466\n#, fuzzy\nmsgid \"Could not send chunked request terminator\"\nmsgstr \"%s: :     : %s\\n\"\n\n#: src/ne_request.c:842\n#, fuzzy, c-format\nmsgid \"Could not parse redirect destination URL\"\nmsgstr \"%s: :     : %s\\n\"\n\n#: src/ne_request.c:848\n#, fuzzy, c-format\nmsgid \"Could not parse request target URI\"\nmsgstr \"%s: :     : %s\\n\"\n\n#: src/ne_request.c:1024\nmsgid \"Could not read chunk size\"\nmsgstr \"\"\n\n#: src/ne_request.c:1027\nmsgid \"Invalid chunk-size line\"\nmsgstr \"\"\n\n#: src/ne_request.c:1045\n#, fuzzy\nmsgid \"Could not parse chunk size\"\nmsgstr \"%s: :     : %s\\n\"\n\n#: src/ne_request.c:1085\nmsgid \"Could not read response body\"\nmsgstr \"\"\n\n#: src/ne_request.c:1101\n#, fuzzy\nmsgid \"Could not read chunk delimiter\"\nmsgstr \"%s: :     : %s\\n\"\n\n#: src/ne_request.c:1104\nmsgid \"Chunk delimiter was invalid\"\nmsgstr \"\"\n\n#: src/ne_request.c:1202\nmsgid \"Could not read status line\"\nmsgstr \"\"\n\n#: src/ne_request.c:1224\n#, fuzzy\nmsgid \"Could not parse response status line\"\nmsgstr \"%s: :     : %s\\n\"\n\n#: src/ne_request.c:1227\nmsgid \"Incompatible HTTP version\"\nmsgstr \"\"\n\n#: src/ne_request.c:1266\nmsgid \"Could not send request\"\nmsgstr \"\"\n\n#: src/ne_request.c:1308\n#, fuzzy\nmsgid \"Timed out reading interim responses\"\nmsgstr \"%s: :     : %s\\n\"\n\n#: src/ne_request.c:1337 src/ne_request.c:1354 src/ne_request.c:1364\nmsgid \"Error reading response headers\"\nmsgstr \"\"\n\n#: src/ne_request.c:1374\n#, c-format\nmsgid \"Response header too long\"\nmsgstr \"\"\n\n#: src/ne_request.c:1507\nmsgid \"Response exceeded maximum number of header fields\"\nmsgstr \"\"\n\n#: src/ne_request.c:1522\n#, fuzzy, c-format\nmsgid \"Could not resolve hostname `%s': %s\"\nmsgstr \"%s: :     : %s.\\n\"\n\n#: src/ne_request.c:1645\nmsgid \"Unknown transfer-coding in response\"\nmsgstr \"\"\n\n#: src/ne_request.c:1660\nmsgid \"Invalid Content-Length in response\"\nmsgstr \"\"\n\n#: src/ne_request.c:1734\n#, fuzzy, c-format\nmsgid \"Could not write to file: %s\"\nmsgstr \"%s: :     : %s\\n\"\n\n#: src/ne_request.c:1777\n#, c-format\nmsgid \"Response buffer size too small\"\nmsgstr \"\"\n\n#: src/ne_request.c:1845\n#, c-format\nmsgid \"Could not create SSL connection through proxy server: %s\"\nmsgstr \"\"\n\n#: src/ne_request.c:1884\n#, fuzzy, c-format\nmsgid \"Could not create socket\"\nmsgstr \"%s: :     : %s\\n\"\n\n#: src/ne_request.c:1920\nmsgid \"Could not connect to server\"\nmsgstr \"\"\n\n#: src/ne_request.c:1922\nmsgid \"Could not connect to proxy server\"\nmsgstr \"\"\n\n#: src/ne_request.c:1965\n#, c-format\nmsgid \"Could not find IPv4 address of hostname %s for SOCKS v4 proxy\"\nmsgstr \"\"\n\n#: src/ne_request.c:2023\n#, c-format\nmsgid \"Could not establish connection from SOCKS proxy (%s:%u): %s\"\nmsgstr \"\"\n\n#: src/ne_session.c:236\n#, fuzzy\nmsgid \"Unknown error.\"\nmsgstr \"  \"\n\n#: src/ne_session.c:615\n#, c-format\nmsgid \"Could not set minimum/maximum SSL/TLS versions\"\nmsgstr \"\"\n\n#: src/ne_session.c:622\n#, c-format\nmsgid \"SSL/TLS not enabled for the session\"\nmsgstr \"\"\n\n#: src/ne_session.c:653 src/ne_session.c:664\nmsgid \"[invalid date]\"\nmsgstr \"\"\n\n#: src/ne_session.c:686 src/ne_socket.c:747\n#, c-format\nmsgid \"SSL error: %s\"\nmsgstr \"\"\n\n#: src/ne_session.c:712\n#, fuzzy, c-format\nmsgid \"SSL handshake failed: %s\"\nmsgstr \"%s: :     : %s\\n\"\n\n#: src/ne_session.c:719\n#, fuzzy, c-format\nmsgid \"No server certificate: %s\"\nmsgstr \"%s: :     : %s\\n\"\n\n#: src/ne_socket.c:527 src/ne_socket.c:680 src/ne_socket.c:834\nmsgid \"Connection closed\"\nmsgstr \"\"\n\n#: src/ne_socket.c:685\nmsgid \"Retry operation\"\nmsgstr \"\"\n\n#: src/ne_socket.c:700 src/ne_socket.c:735 src/ne_socket.c:848\nmsgid \"Secure connection truncated\"\nmsgstr \"\"\n\n#: src/ne_socket.c:705\nmsgid \"Secure connection reset\"\nmsgstr \"\"\n\n#: src/ne_socket.c:710 src/ne_socket.c:718\nmsgid \"Handshake rejected - client certificate was requested\"\nmsgstr \"\"\n\n#: src/ne_socket.c:721\n#, fuzzy\nmsgid \"Handshake failed\"\nmsgstr \"%s: :     : %s\\n\"\n\n#: src/ne_socket.c:750\n#, c-format\nmsgid \"SSL error code %d/%d/%lu\"\nmsgstr \"\"\n\n#: src/ne_socket.c:839\n#, c-format\nmsgid \"SSL alert received: %s\"\nmsgstr \"\"\n\n#: src/ne_socket.c:860\nmsgid \"SSL socket read failed\"\nmsgstr \"\"\n\n#: src/ne_socket.c:864\nmsgid \" (client certificate was requested)\"\nmsgstr \"\"\n\n#: src/ne_socket.c:868\n#, c-format\nmsgid \"SSL error%s: %s\"\nmsgstr \"\"\n\n#: src/ne_socket.c:994\nmsgid \"Line too long\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1155 src/ne_socket.c:1161\nmsgid \"Host not found\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1404\nmsgid \"Connection timed out\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1603\nmsgid \"Socket descriptor number exceeds FD_SETSIZE\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1665\nmsgid \"Socket family not supported\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1825\nmsgid \"certificate is not yet valid\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1826\nmsgid \"certificate has expired\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1827\nmsgid \"certificate issued for a different hostname\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1828\nmsgid \"issuer is not trusted\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1829\nmsgid \"bad certificate chain\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1830\nmsgid \"certificate has been revoked\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1835\nmsgid \"Server certificate verification failed: \"\nmsgstr \"\"\n\n#: src/ne_socket.c:1913\n#, c-format\nmsgid \"SSL error: failed to set priority string at '%s'\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1968\nmsgid \"Client certificate verification failed\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1990\nmsgid \"SSL disabled due to lack of entropy\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1996\nmsgid \"Could not create SSL structure\"\nmsgstr \"\"\n\n#: src/ne_socket.c:2210\nmsgid \"SSL server did not present certificate\"\nmsgstr \"\"\n\n#: src/ne_socket.c:2240\nmsgid \"Missing flags for socket shutdown\"\nmsgstr \"\"\n\n#: src/ne_socket.c:2258 src/ne_socket.c:2269 src/ne_socket.c:2284\nmsgid \"Incomplete TLS closure\"\nmsgstr \"\"\n\n#: src/ne_socks.c:65\nmsgid \"failure\"\nmsgstr \"\"\n\n#: src/ne_socks.c:68\nmsgid \"connection not permitted\"\nmsgstr \"\"\n\n#: src/ne_socks.c:71\nmsgid \"network unreachable\"\nmsgstr \"\"\n\n#: src/ne_socks.c:74\nmsgid \"host unreachable\"\nmsgstr \"\"\n\n#: src/ne_socks.c:77\nmsgid \"TTL expired\"\nmsgstr \"\"\n\n#: src/ne_socks.c:80\nmsgid \"command not supported\"\nmsgstr \"\"\n\n#: src/ne_socks.c:83\nmsgid \"address type not supported\"\nmsgstr \"\"\n\n#: src/ne_socks.c:86\n#, c-format\nmsgid \"%s: unrecognized error (%u)\"\nmsgstr \"\"\n\n#: src/ne_socks.c:128 src/ne_socks.c:328\n#, fuzzy\nmsgid \"Could not send message to proxy\"\nmsgstr \"%s: :     : %s\\n\"\n\n#: src/ne_socks.c:133\n#, fuzzy\nmsgid \"Could not read initial response from proxy\"\nmsgstr \"%s: :     : %s\\n\"\n\n#: src/ne_socks.c:136\nmsgid \"Invalid version in proxy response\"\nmsgstr \"\"\n\n#: src/ne_socks.c:157\n#, fuzzy\nmsgid \"Could not send login message\"\nmsgstr \"%s: :     : %s\\n\"\n\n#: src/ne_socks.c:162\n#, fuzzy\nmsgid \"Could not read login reply\"\nmsgstr \"%s: :     : %s\\n\"\n\n#: src/ne_socks.c:165\nmsgid \"Invalid version in login reply\"\nmsgstr \"\"\n\n#: src/ne_socks.c:168\n#, fuzzy\nmsgid \"Authentication failed\"\nmsgstr \"%s: :     : %s\\n\"\n\n#: src/ne_socks.c:172\nmsgid \"No acceptable authentication method\"\nmsgstr \"\"\n\n#: src/ne_socks.c:174\nmsgid \"Unexpected authentication method chosen\"\nmsgstr \"\"\n\n#: src/ne_socks.c:210\n#, fuzzy\nmsgid \"Could not send connect request\"\nmsgstr \"%s: :     : %s\\n\"\n\n#: src/ne_socks.c:215\n#, fuzzy\nmsgid \"Could not read connect reply\"\nmsgstr \"%s: :     : %s\\n\"\n\n#: src/ne_socks.c:218\nmsgid \"Invalid version in connect reply\"\nmsgstr \"\"\n\n#: src/ne_socks.c:221 src/ne_socks.c:337\n#, fuzzy\nmsgid \"Could not connect\"\nmsgstr \"%s: :     : %s\\n\"\n\n#: src/ne_socks.c:235\nmsgid \"Could not read FQDN length in connect reply\"\nmsgstr \"\"\n\n#: src/ne_socks.c:240\nmsgid \"Unknown address type in connect reply\"\nmsgstr \"\"\n\n#: src/ne_socks.c:245\nmsgid \"Could not read address in connect reply\"\nmsgstr \"\"\n\n#: src/ne_socks.c:266\nmsgid \"request rejected or failed\"\nmsgstr \"\"\n\n#: src/ne_socks.c:269\nmsgid \"could not establish connection to identd\"\nmsgstr \"\"\n\n#: src/ne_socks.c:272\nmsgid \"rejected due to identd user mismatch\"\nmsgstr \"\"\n\n#: src/ne_socks.c:275\n#, c-format\nmsgid \"%s: unrecognized failure (%u)\"\nmsgstr \"\"\n\n#: src/ne_socks.c:333\n#, fuzzy\nmsgid \"Could not read response from proxy\"\nmsgstr \"%s: :     : %s\\n\"\n\n#: src/ne_xml.c:190\n#, c-format\nmsgid \"XML parse error: %s\"\nmsgstr \"\"\n\n#: src/ne_xml.c:305\n#, c-format\nmsgid \"XML parse error at line %d: invalid element name\"\nmsgstr \"\"\n\n#: src/ne_xml.c:499\n#, fuzzy\nmsgid \"Unknown error\"\nmsgstr \"  \"\n\n#: src/ne_xml.c:625\nmsgid \"Invalid Byte Order Mark\"\nmsgstr \"\"\n\n#: src/ne_xml.c:714\n#, c-format\nmsgid \"XML parse error at line %d: %s\"\nmsgstr \"\"\n\n#: src/ne_xmlreq.c:38\n#, fuzzy, c-format\nmsgid \"Could not parse response: %s\"\nmsgstr \"%s: :     : %s\\n\"\n\n#, fuzzy, c-format\n#~ msgid \"%s hash failed for Digest challenge\"\n#~ msgstr \"%s: :     : %s\\n\"\n\n#, fuzzy\n#~ msgid \"Could not read interim response headers\"\n#~ msgstr \"%s: :     : %s\\n\"\n\n#, fuzzy\n#~ msgid \"%s: %s\"\n#~ msgstr \"%s\\n\"\n"
  },
  {
    "path": "po/tr.po",
    "content": "# sitecopy localization for turkish (tr)\n# Copyright (C) 2001 Free Software Foundation, Inc.\n# A. Sinan Unur <sinan@unur.com>, 2001.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: sitecopy-0.10.10\\n\"\n\"Report-Msgid-Bugs-To: https://github.com/notroj/neon\\n\"\n\"POT-Creation-Date: 2026-03-15 08:52+0000\\n\"\n\"PO-Revision-Date: 2001-01-03 HO:MI+ZONE\\n\"\n\"Last-Translator: A. Sinan Unur <sinan@unur.com>\\n\"\n\"Language-Team: tr\\n\"\n\"Language: \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=iso-8859-9\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: src/ne_207.c:231\n#, c-format\nmsgid \"\"\n\"Invalid HTTP status line in status element at line %d of response:\\n\"\n\"Status line was: %s\"\nmsgstr \"\"\n\"Invalid HTTP status line in status element at line %d of response:\\n\"\n\"Status line was: %s\"\n\n#: src/ne_auth.c:130\n#, fuzzy, c-format\nmsgid \"Could not authenticate to server: %s\"\nmsgstr \"Sunucuyla balant kurulamad\"\n\n#: src/ne_auth.c:135\n#, fuzzy, c-format\nmsgid \"Could not authenticate to proxy server: %s\"\nmsgstr \"Ara sunucuyla balant kurulamad\"\n\n#: src/ne_auth.c:338\n#, c-format\nmsgid \"rejected %s challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:379\nmsgid \"missing realm in Basic challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:393\nmsgid \"cannot handle Basic challenge for username containing colon\"\nmsgstr \"\"\n\n#: src/ne_auth.c:496\nmsgid \"invalid Negotiate token\"\nmsgstr \"\"\n\n#: src/ne_auth.c:519\nmsgid \"GSSAPI authentication error: \"\nmsgstr \"\"\n\n#: src/ne_auth.c:532\n#, c-format\nmsgid \"GSSAPI failure (code %u)\"\nmsgstr \"\"\n\n#: src/ne_auth.c:567\nmsgid \"ignoring empty Negotiate continuation\"\nmsgstr \"\"\n\n#: src/ne_auth.c:582\n#, c-format\nmsgid \"Negotiate response verification failed: invalid response header token\"\nmsgstr \"\"\n\n#: src/ne_auth.c:604\n#, c-format\nmsgid \"Negotiate response verification failure: %s\"\nmsgstr \"\"\n\n#: src/ne_auth.c:668\n#, c-format\nmsgid \"SSPI response verification failed: invalid response header token\"\nmsgstr \"\"\n\n#: src/ne_auth.c:794\nmsgid \"unexpected token in NTLM challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:822\nmsgid \"malformed NTLM challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:840\n#, fuzzy\nmsgid \"could not handle NTLM challenge\"\nmsgstr \"Para boyutu anlalamad\"\n\n#: src/ne_auth.c:908\n#, fuzzy\nmsgid \"could not handle non-ASCII username in Digest challenge\"\nmsgstr \"Para boyutu anlalamad\"\n\n#: src/ne_auth.c:936\nmsgid \"unknown algorithm in Digest challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:943\nmsgid \"legacy Digest challenge not supported\"\nmsgstr \"\"\n\n#: src/ne_auth.c:947\nmsgid \"incompatible algorithm in Digest challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:951\nmsgid \"missing parameter in Digest challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:955\nmsgid \"initial Digest challenge was stale\"\nmsgstr \"\"\n\n#: src/ne_auth.c:962\nmsgid \"stale Digest challenge with new algorithm or realm\"\nmsgstr \"\"\n\n#: src/ne_auth.c:969\n#, c-format\nmsgid \"%s algorithm in Digest challenge not supported\"\nmsgstr \"\"\n\n#: src/ne_auth.c:985\n#, fuzzy\nmsgid \"could not parse domain in Digest challenge\"\nmsgstr \"Para boyutu anlalamad\"\n\n#: src/ne_auth.c:992\n#, fuzzy\nmsgid \"cannot create client nonce for Digest challenge\"\nmsgstr \"Para boyutu anlalamad\"\n\n#: src/ne_auth.c:1273\n#, c-format\nmsgid \"Digest mutual authentication failure: missing parameters\"\nmsgstr \"\"\n\n#: src/ne_auth.c:1278\n#, c-format\nmsgid \"Digest mutual authentication failure: client nonce mismatch\"\nmsgstr \"\"\n\n#: src/ne_auth.c:1287\n#, c-format\nmsgid \"Digest mutual authentication failure: could not parse nonce count\"\nmsgstr \"\"\n\n#: src/ne_auth.c:1292\n#, c-format\nmsgid \"Digest mutual authentication failure: nonce count mismatch (%u not %u)\"\nmsgstr \"\"\n\n#: src/ne_auth.c:1319\n#, c-format\nmsgid \"Digest mutual authentication failure: request-digest mismatch\"\nmsgstr \"\"\n\n#: src/ne_auth.c:1453\n#, c-format\nmsgid \"ignored %s challenge\"\nmsgstr \"\"\n\n#: src/ne_auth.c:1550\n#, fuzzy\nmsgid \"could not parse challenge\"\nmsgstr \"Para boyutu anlalamad\"\n\n#: src/ne_basic.c:98\n#, fuzzy, c-format\nmsgid \"Could not determine file size: %s\"\nmsgstr \"Dosya alamad: \"\n\n#: src/ne_basic.c:201\n#, c-format\nmsgid \"Response did not include requested range\"\nmsgstr \"\"\n\n#: src/ne_basic.c:236\n#, c-format\nmsgid \"Range is not satisfiable\"\nmsgstr \"\"\n\n#: src/ne_basic.c:241\n#, fuzzy, c-format\nmsgid \"Resource does not support ranged GET requests\"\nmsgstr \"Sunucu ksmi GET ilemini desteklemiyor.\"\n\n#: src/ne_compress.c:184\n#, c-format\nmsgid \"%s: %s (code %d)\"\nmsgstr \"\"\n\n#: src/ne_compress.c:232\n#, fuzzy\nmsgid \"Could not inflate data\"\nmsgstr \"Dosya alamad: \"\n\n#: src/ne_compress.c:293\n#, fuzzy\nmsgid \"Could not initialize zlib\"\nmsgstr \"Dosyaya yazm yaplamad: \"\n\n#: src/ne_gnutls.c:181\n#, c-format\nmsgid \"[unprintable:#%lu]\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:209\nmsgid \"[unprintable]\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:633\n#, c-format\nmsgid \"Failed to import private key: %s\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:920\nmsgid \"signed using insecure algorithm\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:923\n#, c-format\nmsgid \"unrecognized errors (%u)\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:965 src/ne_openssl.c:496\nmsgid \"Server certificate was missing commonName attribute in subject name\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:979\n#, fuzzy, c-format\nmsgid \"Could not verify server certificate: %s\"\nmsgstr \"%s dosyasna yazm yaplamad\"\n\n#: src/ne_gnutls.c:998 src/ne_openssl.c:487\n#, c-format\nmsgid \"Certificate verification error: %s\"\nmsgstr \"\"\n\n#: src/ne_locks.c:640\nmsgid \"LOCK response missing Lock-Token header\"\nmsgstr \"\"\n\n#: src/ne_locks.c:815\n#, c-format\nmsgid \"Response missing activelock for %s\"\nmsgstr \"\"\n\n#: src/ne_locks.c:860\n#, c-format\nmsgid \"No activelock for <%s> returned in LOCK refresh response\"\nmsgstr \"\"\n\n#: src/ne_props.c:364 src/ne_props.c:428\nmsgid \"Response exceeds maximum property count\"\nmsgstr \"\"\n\n#: src/ne_request.c:210\n#, fuzzy, c-format\nmsgid \"%s: connection was closed by proxy server\"\nmsgstr \"%s: balant ara sunucu tarafinden kesildi.\"\n\n#: src/ne_request.c:213\n#, fuzzy, c-format\nmsgid \"%s: connection was closed by server\"\nmsgstr \"%s: balant sunucu tarafinden kesildi.\"\n\n#: src/ne_request.c:218\n#, fuzzy, c-format\nmsgid \"%s: connection timed out\"\nmsgstr \"%s: balant bekleme snr ald.\"\n\n#: src/ne_request.c:321\n#, fuzzy, c-format\nmsgid \"Premature EOF in request body file\"\nmsgstr \"%s dosyasna yazm yaplamad\"\n\n#: src/ne_request.c:328\n#, fuzzy, c-format\nmsgid \"Failed reading request body file: %s\"\nmsgstr \"%s dosyasna yazm yaplamad\"\n\n#: src/ne_request.c:348\nmsgid \"offset invalid\"\nmsgstr \"\"\n\n#: src/ne_request.c:353\n#, fuzzy, c-format\nmsgid \"Could not seek to offset %s of request body file: %s\"\nmsgstr \"%s dosyasna yazm yaplamad\"\n\n#: src/ne_request.c:439\nmsgid \"Could not send request body\"\nmsgstr \"stek metni gnderilemedi\"\n\n#: src/ne_request.c:466\n#, fuzzy\nmsgid \"Could not send chunked request terminator\"\nmsgstr \"stek gnderilemedi\"\n\n#: src/ne_request.c:842\n#, fuzzy, c-format\nmsgid \"Could not parse redirect destination URL\"\nmsgstr \"Durum satr anlalamad.\"\n\n#: src/ne_request.c:848\n#, fuzzy, c-format\nmsgid \"Could not parse request target URI\"\nmsgstr \"Durum satr anlalamad.\"\n\n#: src/ne_request.c:1024\nmsgid \"Could not read chunk size\"\nmsgstr \"Para boyutu renilemedi\"\n\n#: src/ne_request.c:1027\nmsgid \"Invalid chunk-size line\"\nmsgstr \"\"\n\n#: src/ne_request.c:1045\nmsgid \"Could not parse chunk size\"\nmsgstr \"Para boyutu anlalamad\"\n\n#: src/ne_request.c:1085\nmsgid \"Could not read response body\"\nmsgstr \"Yant metni okunamad\"\n\n#: src/ne_request.c:1101\n#, fuzzy\nmsgid \"Could not read chunk delimiter\"\nmsgstr \"Para boyutu renilemedi\"\n\n#: src/ne_request.c:1104\nmsgid \"Chunk delimiter was invalid\"\nmsgstr \"\"\n\n#: src/ne_request.c:1202\nmsgid \"Could not read status line\"\nmsgstr \"Durum satr okunamad\"\n\n#: src/ne_request.c:1224\n#, fuzzy\nmsgid \"Could not parse response status line\"\nmsgstr \"Durum satr anlalamad.\"\n\n#: src/ne_request.c:1227\nmsgid \"Incompatible HTTP version\"\nmsgstr \"\"\n\n#: src/ne_request.c:1266\nmsgid \"Could not send request\"\nmsgstr \"stek gnderilemedi\"\n\n#: src/ne_request.c:1308\n#, fuzzy\nmsgid \"Timed out reading interim responses\"\nmsgstr \"Yant metni okunamad\"\n\n#: src/ne_request.c:1337 src/ne_request.c:1354 src/ne_request.c:1364\nmsgid \"Error reading response headers\"\nmsgstr \"Yant balklar okunurken hata\"\n\n#: src/ne_request.c:1374\n#, c-format\nmsgid \"Response header too long\"\nmsgstr \"Yant bal ok uzun\"\n\n#: src/ne_request.c:1507\nmsgid \"Response exceeded maximum number of header fields\"\nmsgstr \"\"\n\n#: src/ne_request.c:1522\n#, fuzzy, c-format\nmsgid \"Could not resolve hostname `%s': %s\"\nmsgstr \"%s: Hata: %s sunucusunun adresi bulunamad.\\n\"\n\n#: src/ne_request.c:1645\nmsgid \"Unknown transfer-coding in response\"\nmsgstr \"\"\n\n#: src/ne_request.c:1660\nmsgid \"Invalid Content-Length in response\"\nmsgstr \"\"\n\n#: src/ne_request.c:1734\n#, c-format\nmsgid \"Could not write to file: %s\"\nmsgstr \"%s dosyasna yazm yaplamad\"\n\n#: src/ne_request.c:1777\n#, fuzzy, c-format\nmsgid \"Response buffer size too small\"\nmsgstr \"Yant bal ok uzun\"\n\n#: src/ne_request.c:1845\n#, fuzzy, c-format\nmsgid \"Could not create SSL connection through proxy server: %s\"\nmsgstr \"Ara sunucu zerinden SSL balants kurulamad\"\n\n#: src/ne_request.c:1884\n#, fuzzy, c-format\nmsgid \"Could not create socket\"\nmsgstr \"SSL balants kurulamad\"\n\n#: src/ne_request.c:1920\nmsgid \"Could not connect to server\"\nmsgstr \"Sunucuyla balant kurulamad\"\n\n#: src/ne_request.c:1922\nmsgid \"Could not connect to proxy server\"\nmsgstr \"Ara sunucuyla balant kurulamad\"\n\n#: src/ne_request.c:1965\n#, c-format\nmsgid \"Could not find IPv4 address of hostname %s for SOCKS v4 proxy\"\nmsgstr \"\"\n\n#: src/ne_request.c:2023\n#, fuzzy, c-format\nmsgid \"Could not establish connection from SOCKS proxy (%s:%u): %s\"\nmsgstr \"Ara sunucu zerinden SSL balants kurulamad\"\n\n#: src/ne_session.c:236\n#, fuzzy\nmsgid \"Unknown error.\"\nmsgstr \"Bilinmeyen sistem hatas\"\n\n#: src/ne_session.c:615\n#, c-format\nmsgid \"Could not set minimum/maximum SSL/TLS versions\"\nmsgstr \"\"\n\n#: src/ne_session.c:622\n#, c-format\nmsgid \"SSL/TLS not enabled for the session\"\nmsgstr \"\"\n\n#: src/ne_session.c:653 src/ne_session.c:664\nmsgid \"[invalid date]\"\nmsgstr \"\"\n\n#: src/ne_session.c:686 src/ne_socket.c:747\n#, fuzzy, c-format\nmsgid \"SSL error: %s\"\nmsgstr \"%s: Hata: %s\\n\"\n\n#: src/ne_session.c:712\n#, fuzzy, c-format\nmsgid \"SSL handshake failed: %s\"\nmsgstr \"%s dosyasna yazm yaplamad\"\n\n#: src/ne_session.c:719\n#, fuzzy, c-format\nmsgid \"No server certificate: %s\"\nmsgstr \"%s dosyasna yazm yaplamad\"\n\n#: src/ne_socket.c:527 src/ne_socket.c:680 src/ne_socket.c:834\n#, fuzzy\nmsgid \"Connection closed\"\nmsgstr \"Balant sunucu tarafndan kesildi\"\n\n#: src/ne_socket.c:685\nmsgid \"Retry operation\"\nmsgstr \"\"\n\n#: src/ne_socket.c:700 src/ne_socket.c:735 src/ne_socket.c:848\n#, fuzzy\nmsgid \"Secure connection truncated\"\nmsgstr \"Balant sre snr ald.\"\n\n#: src/ne_socket.c:705\n#, fuzzy\nmsgid \"Secure connection reset\"\nmsgstr \"Balant sre snr ald.\"\n\n#: src/ne_socket.c:710 src/ne_socket.c:718\nmsgid \"Handshake rejected - client certificate was requested\"\nmsgstr \"\"\n\n#: src/ne_socket.c:721\n#, fuzzy\nmsgid \"Handshake failed\"\nmsgstr \"%s dosyasna yazm yaplamad\"\n\n#: src/ne_socket.c:750\n#, c-format\nmsgid \"SSL error code %d/%d/%lu\"\nmsgstr \"\"\n\n#: src/ne_socket.c:839\n#, fuzzy, c-format\nmsgid \"SSL alert received: %s\"\nmsgstr \"%s: Hata: %s\\n\"\n\n#: src/ne_socket.c:860\nmsgid \"SSL socket read failed\"\nmsgstr \"\"\n\n#: src/ne_socket.c:864\nmsgid \" (client certificate was requested)\"\nmsgstr \"\"\n\n#: src/ne_socket.c:868\n#, fuzzy, c-format\nmsgid \"SSL error%s: %s\"\nmsgstr \"%s: Hata: %s\\n\"\n\n#: src/ne_socket.c:994\nmsgid \"Line too long\"\nmsgstr \"Satr ok uzun\"\n\n#: src/ne_socket.c:1155 src/ne_socket.c:1161\nmsgid \"Host not found\"\nmsgstr \"Sunucu bulunamad\"\n\n#: src/ne_socket.c:1404\n#, fuzzy\nmsgid \"Connection timed out\"\nmsgstr \"%s: balant bekleme snr ald.\"\n\n#: src/ne_socket.c:1603\nmsgid \"Socket descriptor number exceeds FD_SETSIZE\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1665\nmsgid \"Socket family not supported\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1825\nmsgid \"certificate is not yet valid\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1826\nmsgid \"certificate has expired\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1827\nmsgid \"certificate issued for a different hostname\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1828\nmsgid \"issuer is not trusted\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1829\nmsgid \"bad certificate chain\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1830\nmsgid \"certificate has been revoked\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1835\nmsgid \"Server certificate verification failed: \"\nmsgstr \"\"\n\n#: src/ne_socket.c:1913\n#, c-format\nmsgid \"SSL error: failed to set priority string at '%s'\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1968\nmsgid \"Client certificate verification failed\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1990\nmsgid \"SSL disabled due to lack of entropy\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1996\n#, fuzzy\nmsgid \"Could not create SSL structure\"\nmsgstr \"SSL balants kurulamad\"\n\n#: src/ne_socket.c:2210\nmsgid \"SSL server did not present certificate\"\nmsgstr \"\"\n\n#: src/ne_socket.c:2240\nmsgid \"Missing flags for socket shutdown\"\nmsgstr \"\"\n\n#: src/ne_socket.c:2258 src/ne_socket.c:2269 src/ne_socket.c:2284\nmsgid \"Incomplete TLS closure\"\nmsgstr \"\"\n\n#: src/ne_socks.c:65\nmsgid \"failure\"\nmsgstr \"\"\n\n#: src/ne_socks.c:68\n#, fuzzy\nmsgid \"connection not permitted\"\nmsgstr \"%s: balant bekleme snr ald.\"\n\n#: src/ne_socks.c:71\nmsgid \"network unreachable\"\nmsgstr \"\"\n\n#: src/ne_socks.c:74\nmsgid \"host unreachable\"\nmsgstr \"\"\n\n#: src/ne_socks.c:77\nmsgid \"TTL expired\"\nmsgstr \"\"\n\n#: src/ne_socks.c:80\nmsgid \"command not supported\"\nmsgstr \"\"\n\n#: src/ne_socks.c:83\nmsgid \"address type not supported\"\nmsgstr \"\"\n\n#: src/ne_socks.c:86\n#, c-format\nmsgid \"%s: unrecognized error (%u)\"\nmsgstr \"\"\n\n#: src/ne_socks.c:128 src/ne_socks.c:328\n#, fuzzy\nmsgid \"Could not send message to proxy\"\nmsgstr \"stek metni gnderilemedi\"\n\n#: src/ne_socks.c:133\n#, fuzzy\nmsgid \"Could not read initial response from proxy\"\nmsgstr \"Yant metni okunamad\"\n\n#: src/ne_socks.c:136\nmsgid \"Invalid version in proxy response\"\nmsgstr \"\"\n\n#: src/ne_socks.c:157\n#, fuzzy\nmsgid \"Could not send login message\"\nmsgstr \"stek gnderilemedi\"\n\n#: src/ne_socks.c:162\n#, fuzzy\nmsgid \"Could not read login reply\"\nmsgstr \"Durum satr okunamad\"\n\n#: src/ne_socks.c:165\nmsgid \"Invalid version in login reply\"\nmsgstr \"\"\n\n#: src/ne_socks.c:168\n#, fuzzy\nmsgid \"Authentication failed\"\nmsgstr \"%s dosyasna yazm yaplamad\"\n\n#: src/ne_socks.c:172\nmsgid \"No acceptable authentication method\"\nmsgstr \"\"\n\n#: src/ne_socks.c:174\nmsgid \"Unexpected authentication method chosen\"\nmsgstr \"\"\n\n#: src/ne_socks.c:210\n#, fuzzy\nmsgid \"Could not send connect request\"\nmsgstr \"stek gnderilemedi\"\n\n#: src/ne_socks.c:215\n#, fuzzy\nmsgid \"Could not read connect reply\"\nmsgstr \"Sunucuyla balant kurulamad\"\n\n#: src/ne_socks.c:218\nmsgid \"Invalid version in connect reply\"\nmsgstr \"\"\n\n#: src/ne_socks.c:221 src/ne_socks.c:337\n#, fuzzy\nmsgid \"Could not connect\"\nmsgstr \"Sunucuyla balant kurulamad\"\n\n#: src/ne_socks.c:235\nmsgid \"Could not read FQDN length in connect reply\"\nmsgstr \"\"\n\n#: src/ne_socks.c:240\nmsgid \"Unknown address type in connect reply\"\nmsgstr \"\"\n\n#: src/ne_socks.c:245\n#, fuzzy\nmsgid \"Could not read address in connect reply\"\nmsgstr \"Yant metni okunamad\"\n\n#: src/ne_socks.c:266\nmsgid \"request rejected or failed\"\nmsgstr \"\"\n\n#: src/ne_socks.c:269\n#, fuzzy\nmsgid \"could not establish connection to identd\"\nmsgstr \"Sunucuyla balant kurulamad\"\n\n#: src/ne_socks.c:272\nmsgid \"rejected due to identd user mismatch\"\nmsgstr \"\"\n\n#: src/ne_socks.c:275\n#, c-format\nmsgid \"%s: unrecognized failure (%u)\"\nmsgstr \"\"\n\n#: src/ne_socks.c:333\n#, fuzzy\nmsgid \"Could not read response from proxy\"\nmsgstr \"Yant metni okunamad\"\n\n#: src/ne_xml.c:190\n#, fuzzy, c-format\nmsgid \"XML parse error: %s\"\nmsgstr \"\"\n\"%s: kurulum dosyasnda bozukluk var. satr %d:\\n\"\n\"%s\\n\"\n\n#: src/ne_xml.c:305\n#, fuzzy, c-format\nmsgid \"XML parse error at line %d: invalid element name\"\nmsgstr \"\"\n\"%s: kurulum dosyasnda bozukluk var. satr %d:\\n\"\n\"%s\\n\"\n\n#: src/ne_xml.c:499\n#, fuzzy\nmsgid \"Unknown error\"\nmsgstr \"Bilinmeyen sistem hatas\"\n\n#: src/ne_xml.c:625\nmsgid \"Invalid Byte Order Mark\"\nmsgstr \"\"\n\n#: src/ne_xml.c:714\n#, fuzzy, c-format\nmsgid \"XML parse error at line %d: %s\"\nmsgstr \"\"\n\"%s: kurulum dosyasnda bozukluk var. satr %d:\\n\"\n\"%s\\n\"\n\n#: src/ne_xmlreq.c:38\n#, fuzzy, c-format\nmsgid \"Could not parse response: %s\"\nmsgstr \"Yant metni okunamad\"\n\n#, fuzzy, c-format\n#~ msgid \"%s hash failed for Digest challenge\"\n#~ msgstr \"Para boyutu anlalamad\"\n\n#, fuzzy\n#~ msgid \"Could not read interim response headers\"\n#~ msgstr \"Yant metni okunamad\"\n\n#, fuzzy\n#~ msgid \"%s: %s\"\n#~ msgstr \"%s: Hata: %s\\n\"\n\n#~ msgid \"Server was not authenticated correctly.\"\n#~ msgstr \"Server was not authenticated correctly.\"\n\n#~ msgid \"Proxy server was not authenticated correctly.\"\n#~ msgstr \"Proxy server was not authenticated correctly.\"\n"
  },
  {
    "path": "po/zh_CN.po",
    "content": "# Simplified chinese message for neon\n#\n# Copyright (C) 2006-2008 Free Software Foundation, Inc.\n# This file is distributed under the same license as the neon package.\n#\n# Dongsheng Song <dongsheng.song@gmail.com>, 2006-2008\n#\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: neon 0.29.x\\n\"\n\"Report-Msgid-Bugs-To: https://github.com/notroj/neon\\n\"\n\"POT-Creation-Date: 2026-03-15 08:52+0000\\n\"\n\"PO-Revision-Date: 2008-03-03 11:20+0800\\n\"\n\"Last-Translator: Dongsheng Song <dongsheng.song@gmail.com>\\n\"\n\"Language-Team: neon@webdav.org\\n\"\n\"Language: \\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\n#: src/ne_207.c:231\n#, c-format\nmsgid \"\"\n\"Invalid HTTP status line in status element at line %d of response:\\n\"\n\"Status line was: %s\"\nmsgstr \"\"\n\"响应信息中 %d 行的状态元素中发现非法 HTTP 状态行：\\n\"\n\"状态行是: %s\"\n\n#: src/ne_auth.c:130\n#, c-format\nmsgid \"Could not authenticate to server: %s\"\nmsgstr \"不能认证到服务器: %s\"\n\n#: src/ne_auth.c:135\n#, c-format\nmsgid \"Could not authenticate to proxy server: %s\"\nmsgstr \"不能认证到代理服务器: %s\"\n\n#: src/ne_auth.c:338\n#, c-format\nmsgid \"rejected %s challenge\"\nmsgstr \"被拒绝的 %s 挑战\"\n\n#: src/ne_auth.c:379\nmsgid \"missing realm in Basic challenge\"\nmsgstr \"在基本挑战中丢失了领域\"\n\n#: src/ne_auth.c:393\nmsgid \"cannot handle Basic challenge for username containing colon\"\nmsgstr \"\"\n\n#: src/ne_auth.c:496\nmsgid \"invalid Negotiate token\"\nmsgstr \"非法磋商令牌\"\n\n#: src/ne_auth.c:519\nmsgid \"GSSAPI authentication error: \"\nmsgstr \"GSSAPI 认证错误: \"\n\n#: src/ne_auth.c:532\n#, c-format\nmsgid \"GSSAPI failure (code %u)\"\nmsgstr \"GSSAPI 失败(代码 %u)\"\n\n#: src/ne_auth.c:567\nmsgid \"ignoring empty Negotiate continuation\"\nmsgstr \"忽略后续的空磋商\"\n\n#: src/ne_auth.c:582\n#, c-format\nmsgid \"Negotiate response verification failed: invalid response header token\"\nmsgstr \"校验协商响应失败：非法响应头令牌\"\n\n#: src/ne_auth.c:604\n#, c-format\nmsgid \"Negotiate response verification failure: %s\"\nmsgstr \"磋商响应校验失败: %s\"\n\n#: src/ne_auth.c:668\n#, fuzzy, c-format\nmsgid \"SSPI response verification failed: invalid response header token\"\nmsgstr \"校验协商响应失败：非法响应头令牌\"\n\n#: src/ne_auth.c:794\n#, fuzzy\nmsgid \"unexpected token in NTLM challenge\"\nmsgstr \"被拒绝的 %s 挑战\"\n\n#: src/ne_auth.c:822\n#, fuzzy\nmsgid \"malformed NTLM challenge\"\nmsgstr \"被忽略的 %s 挑战\"\n\n#: src/ne_auth.c:840\n#, fuzzy\nmsgid \"could not handle NTLM challenge\"\nmsgstr \"不能解析挑战\"\n\n#: src/ne_auth.c:908\n#, fuzzy\nmsgid \"could not handle non-ASCII username in Digest challenge\"\nmsgstr \"在摘要挑战中的不能解析域\"\n\n#: src/ne_auth.c:936\nmsgid \"unknown algorithm in Digest challenge\"\nmsgstr \"在摘要挑战中的算法不可识别\"\n\n#: src/ne_auth.c:943\n#, fuzzy\nmsgid \"legacy Digest challenge not supported\"\nmsgstr \"陈旧的初始化摘要挑战\"\n\n#: src/ne_auth.c:947\nmsgid \"incompatible algorithm in Digest challenge\"\nmsgstr \"在摘要挑战中的算法不兼容\"\n\n#: src/ne_auth.c:951\nmsgid \"missing parameter in Digest challenge\"\nmsgstr \"在摘要挑战中的参数丢失\"\n\n#: src/ne_auth.c:955\nmsgid \"initial Digest challenge was stale\"\nmsgstr \"陈旧的初始化摘要挑战\"\n\n#: src/ne_auth.c:962\nmsgid \"stale Digest challenge with new algorithm or realm\"\nmsgstr \"陈旧的摘要挑战用于新算法或新领域\"\n\n#: src/ne_auth.c:969\n#, fuzzy, c-format\nmsgid \"%s algorithm in Digest challenge not supported\"\nmsgstr \"在摘要挑战中的算法不可识别\"\n\n#: src/ne_auth.c:985\nmsgid \"could not parse domain in Digest challenge\"\nmsgstr \"在摘要挑战中的不能解析域\"\n\n#: src/ne_auth.c:992\n#, fuzzy\nmsgid \"cannot create client nonce for Digest challenge\"\nmsgstr \"在摘要挑战中的不能解析域\"\n\n#: src/ne_auth.c:1273\n#, c-format\nmsgid \"Digest mutual authentication failure: missing parameters\"\nmsgstr \"摘要互相认证失败：参数遗漏\"\n\n#: src/ne_auth.c:1278\n#, c-format\nmsgid \"Digest mutual authentication failure: client nonce mismatch\"\nmsgstr \"摘要互相认证失败：客户现时不匹配\"\n\n#: src/ne_auth.c:1287\n#, c-format\nmsgid \"Digest mutual authentication failure: could not parse nonce count\"\nmsgstr \"摘要互相认证失败：不能解析现时计数\"\n\n#: src/ne_auth.c:1292\n#, c-format\nmsgid \"Digest mutual authentication failure: nonce count mismatch (%u not %u)\"\nmsgstr \"摘要互相认证失败：现时计算不匹配 (应该是 %u，不是 %u)\"\n\n#: src/ne_auth.c:1319\n#, c-format\nmsgid \"Digest mutual authentication failure: request-digest mismatch\"\nmsgstr \"摘要互相认证失败：请求摘要不匹配\"\n\n#: src/ne_auth.c:1453\n#, c-format\nmsgid \"ignored %s challenge\"\nmsgstr \"被忽略的 %s 挑战\"\n\n#: src/ne_auth.c:1550\nmsgid \"could not parse challenge\"\nmsgstr \"不能解析挑战\"\n\n#: src/ne_basic.c:98\n#, c-format\nmsgid \"Could not determine file size: %s\"\nmsgstr \"不能确定的文件大小：%s\"\n\n#: src/ne_basic.c:201\n#, c-format\nmsgid \"Response did not include requested range\"\nmsgstr \"响应没有包含请求范围\"\n\n#: src/ne_basic.c:236\n#, c-format\nmsgid \"Range is not satisfiable\"\nmsgstr \"不能满足的范围\"\n\n#: src/ne_basic.c:241\n#, c-format\nmsgid \"Resource does not support ranged GET requests\"\nmsgstr \"资源不支持范围读取\"\n\n#: src/ne_compress.c:184\n#, c-format\nmsgid \"%s: %s (code %d)\"\nmsgstr \"%s： %s (代码 %d)\"\n\n#: src/ne_compress.c:232\nmsgid \"Could not inflate data\"\nmsgstr \"解压数据失败\"\n\n#: src/ne_compress.c:293\nmsgid \"Could not initialize zlib\"\nmsgstr \"初始化 zlib 失败\"\n\n#: src/ne_gnutls.c:181\n#, c-format\nmsgid \"[unprintable:#%lu]\"\nmsgstr \"[非打印字符:#%lu]\"\n\n#: src/ne_gnutls.c:209\nmsgid \"[unprintable]\"\nmsgstr \"[非打印字符]\"\n\n#: src/ne_gnutls.c:633\n#, c-format\nmsgid \"Failed to import private key: %s\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:920\nmsgid \"signed using insecure algorithm\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:923\n#, c-format\nmsgid \"unrecognized errors (%u)\"\nmsgstr \"\"\n\n#: src/ne_gnutls.c:965 src/ne_openssl.c:496\nmsgid \"Server certificate was missing commonName attribute in subject name\"\nmsgstr \"服务器证书在主题名称遗漏了属性 commonName\"\n\n#: src/ne_gnutls.c:979\n#, fuzzy, c-format\nmsgid \"Could not verify server certificate: %s\"\nmsgstr \"不能写入文件：%s\"\n\n#: src/ne_gnutls.c:998 src/ne_openssl.c:487\n#, c-format\nmsgid \"Certificate verification error: %s\"\nmsgstr \"证书校验失败：%s\"\n\n#: src/ne_locks.c:640\nmsgid \"LOCK response missing Lock-Token header\"\nmsgstr \"LOCK 的响应遗漏了 Lock-Token 行\"\n\n#: src/ne_locks.c:815\n#, c-format\nmsgid \"Response missing activelock for %s\"\nmsgstr \"锁定 %s 的响应遗漏了主动锁\"\n\n#: src/ne_locks.c:860\n#, c-format\nmsgid \"No activelock for <%s> returned in LOCK refresh response\"\nmsgstr \"刷新锁定 %s 的响应没有返回主动锁\"\n\n#: src/ne_props.c:364 src/ne_props.c:428\nmsgid \"Response exceeds maximum property count\"\nmsgstr \"响应超过了属性的最大计数\"\n\n#: src/ne_request.c:210\n#, c-format\nmsgid \"%s: connection was closed by proxy server\"\nmsgstr \"%s: 连接被代理服务器关闭\"\n\n#: src/ne_request.c:213\n#, c-format\nmsgid \"%s: connection was closed by server\"\nmsgstr \"%s: 连接被服务器关闭\"\n\n#: src/ne_request.c:218\n#, c-format\nmsgid \"%s: connection timed out\"\nmsgstr \"%s: 连接超时\"\n\n#: src/ne_request.c:321\n#, c-format\nmsgid \"Premature EOF in request body file\"\nmsgstr \"\"\n\n#: src/ne_request.c:328\n#, c-format\nmsgid \"Failed reading request body file: %s\"\nmsgstr \"\"\n\n#: src/ne_request.c:348\nmsgid \"offset invalid\"\nmsgstr \"非法偏移\"\n\n#: src/ne_request.c:353\n#, c-format\nmsgid \"Could not seek to offset %s of request body file: %s\"\nmsgstr \"在请求主体文件不能定位到偏移 %s： %s\"\n\n#: src/ne_request.c:439\nmsgid \"Could not send request body\"\nmsgstr \"不能发送请求主体\"\n\n#: src/ne_request.c:466\n#, fuzzy\nmsgid \"Could not send chunked request terminator\"\nmsgstr \"不能发送请求\"\n\n#: src/ne_request.c:842\n#, c-format\nmsgid \"Could not parse redirect destination URL\"\nmsgstr \"不能解析重定向 URL\"\n\n#: src/ne_request.c:848\n#, fuzzy, c-format\nmsgid \"Could not parse request target URI\"\nmsgstr \"不能解析重定向 URL\"\n\n#: src/ne_request.c:1024\nmsgid \"Could not read chunk size\"\nmsgstr \"不能读块大小\"\n\n#: src/ne_request.c:1027\nmsgid \"Invalid chunk-size line\"\nmsgstr \"\"\n\n#: src/ne_request.c:1045\nmsgid \"Could not parse chunk size\"\nmsgstr \"不能解析块大小\"\n\n#: src/ne_request.c:1085\nmsgid \"Could not read response body\"\nmsgstr \"不能读取响应主体\"\n\n#: src/ne_request.c:1101\nmsgid \"Could not read chunk delimiter\"\nmsgstr \"不能读块分割符\"\n\n#: src/ne_request.c:1104\nmsgid \"Chunk delimiter was invalid\"\nmsgstr \"非法的分割符\"\n\n#: src/ne_request.c:1202\nmsgid \"Could not read status line\"\nmsgstr \"不能读状态行\"\n\n#: src/ne_request.c:1224\nmsgid \"Could not parse response status line\"\nmsgstr \"不能解析响应状态行\"\n\n#: src/ne_request.c:1227\nmsgid \"Incompatible HTTP version\"\nmsgstr \"\"\n\n#: src/ne_request.c:1266\nmsgid \"Could not send request\"\nmsgstr \"不能发送请求\"\n\n#: src/ne_request.c:1308\n#, fuzzy\nmsgid \"Timed out reading interim responses\"\nmsgstr \"不能读临时响应头\"\n\n#: src/ne_request.c:1337 src/ne_request.c:1354 src/ne_request.c:1364\nmsgid \"Error reading response headers\"\nmsgstr \"读取响应头出错\"\n\n#: src/ne_request.c:1374\n#, c-format\nmsgid \"Response header too long\"\nmsgstr \"响应头太长\"\n\n#: src/ne_request.c:1507\nmsgid \"Response exceeded maximum number of header fields\"\nmsgstr \"响应头的域数量超出了最大数量\"\n\n#: src/ne_request.c:1522\n#, c-format\nmsgid \"Could not resolve hostname `%s': %s\"\nmsgstr \"不能解析主机名称 “%s”: %s\"\n\n#: src/ne_request.c:1645\nmsgid \"Unknown transfer-coding in response\"\nmsgstr \"响应中的传输代码未知\"\n\n#: src/ne_request.c:1660\nmsgid \"Invalid Content-Length in response\"\nmsgstr \"非法的 Content-Length 响应域\"\n\n#: src/ne_request.c:1734\n#, c-format\nmsgid \"Could not write to file: %s\"\nmsgstr \"不能写入文件：%s\"\n\n#: src/ne_request.c:1777\n#, fuzzy, c-format\nmsgid \"Response buffer size too small\"\nmsgstr \"响应头太长\"\n\n#: src/ne_request.c:1845\n#, c-format\nmsgid \"Could not create SSL connection through proxy server: %s\"\nmsgstr \"不能通过代理服务器 “%s” 创建 SSL 连接\"\n\n#: src/ne_request.c:1884\n#, c-format\nmsgid \"Could not create socket\"\nmsgstr \"不能创建套接字\"\n\n#: src/ne_request.c:1920\nmsgid \"Could not connect to server\"\nmsgstr \"不能连接到服务器\"\n\n#: src/ne_request.c:1922\nmsgid \"Could not connect to proxy server\"\nmsgstr \"不能连接到代理服务器\"\n\n#: src/ne_request.c:1965\n#, c-format\nmsgid \"Could not find IPv4 address of hostname %s for SOCKS v4 proxy\"\nmsgstr \"\"\n\n#: src/ne_request.c:2023\n#, fuzzy, c-format\nmsgid \"Could not establish connection from SOCKS proxy (%s:%u): %s\"\nmsgstr \"不能通过代理服务器 “%s” 创建 SSL 连接\"\n\n#: src/ne_session.c:236\n#, fuzzy\nmsgid \"Unknown error.\"\nmsgstr \"未知错误\"\n\n#: src/ne_session.c:615\n#, c-format\nmsgid \"Could not set minimum/maximum SSL/TLS versions\"\nmsgstr \"\"\n\n#: src/ne_session.c:622\n#, c-format\nmsgid \"SSL/TLS not enabled for the session\"\nmsgstr \"\"\n\n#: src/ne_session.c:653 src/ne_session.c:664\nmsgid \"[invalid date]\"\nmsgstr \"[非法日期]\"\n\n#: src/ne_session.c:686 src/ne_socket.c:747\n#, c-format\nmsgid \"SSL error: %s\"\nmsgstr \"SSL 错误：%s\"\n\n#: src/ne_session.c:712\n#, fuzzy, c-format\nmsgid \"SSL handshake failed: %s\"\nmsgstr \"SSL 协商失败：%s\"\n\n#: src/ne_session.c:719\n#, fuzzy, c-format\nmsgid \"No server certificate: %s\"\nmsgstr \"不能写入文件：%s\"\n\n#: src/ne_socket.c:527 src/ne_socket.c:680 src/ne_socket.c:834\nmsgid \"Connection closed\"\nmsgstr \"连接关闭\"\n\n#: src/ne_socket.c:685\nmsgid \"Retry operation\"\nmsgstr \"\"\n\n#: src/ne_socket.c:700 src/ne_socket.c:735 src/ne_socket.c:848\nmsgid \"Secure connection truncated\"\nmsgstr \"安全连接切断\"\n\n#: src/ne_socket.c:705\n#, fuzzy\nmsgid \"Secure connection reset\"\nmsgstr \"安全连接切断\"\n\n#: src/ne_socket.c:710 src/ne_socket.c:718\nmsgid \"Handshake rejected - client certificate was requested\"\nmsgstr \"\"\n\n#: src/ne_socket.c:721\n#, fuzzy\nmsgid \"Handshake failed\"\nmsgstr \"SSL 协商失败：%s\"\n\n#: src/ne_socket.c:750\n#, c-format\nmsgid \"SSL error code %d/%d/%lu\"\nmsgstr \"SSL 错误代码 %d/%d/%lu\"\n\n#: src/ne_socket.c:839\n#, c-format\nmsgid \"SSL alert received: %s\"\nmsgstr \"收到 SSL 警报： %s\"\n\n#: src/ne_socket.c:860\nmsgid \"SSL socket read failed\"\nmsgstr \"SSL 套接字读取失败\"\n\n#: src/ne_socket.c:864\n#, fuzzy\nmsgid \" (client certificate was requested)\"\nmsgstr \"证书已经过时\"\n\n#: src/ne_socket.c:868\n#, fuzzy, c-format\nmsgid \"SSL error%s: %s\"\nmsgstr \"SSL 错误：%s\"\n\n#: src/ne_socket.c:994\nmsgid \"Line too long\"\nmsgstr \"行太长\"\n\n#: src/ne_socket.c:1155 src/ne_socket.c:1161\nmsgid \"Host not found\"\nmsgstr \"没有发现主机\"\n\n#: src/ne_socket.c:1404\nmsgid \"Connection timed out\"\nmsgstr \"连接超时\"\n\n#: src/ne_socket.c:1603\nmsgid \"Socket descriptor number exceeds FD_SETSIZE\"\nmsgstr \"套接字数量超过 FD_SETSIZE\"\n\n#: src/ne_socket.c:1665\nmsgid \"Socket family not supported\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1825\nmsgid \"certificate is not yet valid\"\nmsgstr \"证书还未生效\"\n\n#: src/ne_socket.c:1826\nmsgid \"certificate has expired\"\nmsgstr \"证书已经过时\"\n\n#: src/ne_socket.c:1827\nmsgid \"certificate issued for a different hostname\"\nmsgstr \"此证书是为不同的主机名称颁发\"\n\n#: src/ne_socket.c:1828\nmsgid \"issuer is not trusted\"\nmsgstr \"证书发行者不被信任\"\n\n#: src/ne_socket.c:1829\n#, fuzzy\nmsgid \"bad certificate chain\"\nmsgstr \"证书已经过时\"\n\n#: src/ne_socket.c:1830\n#, fuzzy\nmsgid \"certificate has been revoked\"\nmsgstr \"证书已经过时\"\n\n#: src/ne_socket.c:1835\nmsgid \"Server certificate verification failed: \"\nmsgstr \"服务器证书校验失败\"\n\n#: src/ne_socket.c:1913\n#, c-format\nmsgid \"SSL error: failed to set priority string at '%s'\"\nmsgstr \"\"\n\n#: src/ne_socket.c:1968\nmsgid \"Client certificate verification failed\"\nmsgstr \"客户证书校验失败\"\n\n#: src/ne_socket.c:1990\nmsgid \"SSL disabled due to lack of entropy\"\nmsgstr \"由于缺少熵，SSL 已经禁用\"\n\n#: src/ne_socket.c:1996\nmsgid \"Could not create SSL structure\"\nmsgstr \"不能创建 SSL 结构\"\n\n#: src/ne_socket.c:2210\nmsgid \"SSL server did not present certificate\"\nmsgstr \"SSL 服务器不能呈现证书\"\n\n#: src/ne_socket.c:2240\nmsgid \"Missing flags for socket shutdown\"\nmsgstr \"\"\n\n#: src/ne_socket.c:2258 src/ne_socket.c:2269 src/ne_socket.c:2284\nmsgid \"Incomplete TLS closure\"\nmsgstr \"\"\n\n#: src/ne_socks.c:65\nmsgid \"failure\"\nmsgstr \"\"\n\n#: src/ne_socks.c:68\n#, fuzzy\nmsgid \"connection not permitted\"\nmsgstr \"连接超时\"\n\n#: src/ne_socks.c:71\nmsgid \"network unreachable\"\nmsgstr \"\"\n\n#: src/ne_socks.c:74\nmsgid \"host unreachable\"\nmsgstr \"\"\n\n#: src/ne_socks.c:77\nmsgid \"TTL expired\"\nmsgstr \"\"\n\n#: src/ne_socks.c:80\nmsgid \"command not supported\"\nmsgstr \"\"\n\n#: src/ne_socks.c:83\nmsgid \"address type not supported\"\nmsgstr \"\"\n\n#: src/ne_socks.c:86\n#, c-format\nmsgid \"%s: unrecognized error (%u)\"\nmsgstr \"\"\n\n#: src/ne_socks.c:128 src/ne_socks.c:328\n#, fuzzy\nmsgid \"Could not send message to proxy\"\nmsgstr \"不能发送请求主体\"\n\n#: src/ne_socks.c:133\n#, fuzzy\nmsgid \"Could not read initial response from proxy\"\nmsgstr \"不能读取响应主体\"\n\n#: src/ne_socks.c:136\n#, fuzzy\nmsgid \"Invalid version in proxy response\"\nmsgstr \"非法的 Content-Length 响应域\"\n\n#: src/ne_socks.c:157\n#, fuzzy\nmsgid \"Could not send login message\"\nmsgstr \"不能发送请求\"\n\n#: src/ne_socks.c:162\n#, fuzzy\nmsgid \"Could not read login reply\"\nmsgstr \"不能读状态行\"\n\n#: src/ne_socks.c:165\nmsgid \"Invalid version in login reply\"\nmsgstr \"\"\n\n#: src/ne_socks.c:168\n#, fuzzy\nmsgid \"Authentication failed\"\nmsgstr \"GSSAPI 认证错误: \"\n\n#: src/ne_socks.c:172\nmsgid \"No acceptable authentication method\"\nmsgstr \"\"\n\n#: src/ne_socks.c:174\nmsgid \"Unexpected authentication method chosen\"\nmsgstr \"\"\n\n#: src/ne_socks.c:210\n#, fuzzy\nmsgid \"Could not send connect request\"\nmsgstr \"不能发送请求\"\n\n#: src/ne_socks.c:215\n#, fuzzy\nmsgid \"Could not read connect reply\"\nmsgstr \"不能连接到服务器\"\n\n#: src/ne_socks.c:218\nmsgid \"Invalid version in connect reply\"\nmsgstr \"\"\n\n#: src/ne_socks.c:221 src/ne_socks.c:337\n#, fuzzy\nmsgid \"Could not connect\"\nmsgstr \"不能连接到服务器\"\n\n#: src/ne_socks.c:235\nmsgid \"Could not read FQDN length in connect reply\"\nmsgstr \"\"\n\n#: src/ne_socks.c:240\nmsgid \"Unknown address type in connect reply\"\nmsgstr \"\"\n\n#: src/ne_socks.c:245\n#, fuzzy\nmsgid \"Could not read address in connect reply\"\nmsgstr \"不能读取响应主体\"\n\n#: src/ne_socks.c:266\nmsgid \"request rejected or failed\"\nmsgstr \"\"\n\n#: src/ne_socks.c:269\n#, fuzzy\nmsgid \"could not establish connection to identd\"\nmsgstr \"不能连接到服务器\"\n\n#: src/ne_socks.c:272\nmsgid \"rejected due to identd user mismatch\"\nmsgstr \"\"\n\n#: src/ne_socks.c:275\n#, c-format\nmsgid \"%s: unrecognized failure (%u)\"\nmsgstr \"\"\n\n#: src/ne_socks.c:333\n#, fuzzy\nmsgid \"Could not read response from proxy\"\nmsgstr \"不能读取响应主体\"\n\n#: src/ne_xml.c:190\n#, fuzzy, c-format\nmsgid \"XML parse error: %s\"\nmsgstr \"在 %d 行解析 XML 错误: %s\"\n\n#: src/ne_xml.c:305\n#, c-format\nmsgid \"XML parse error at line %d: invalid element name\"\nmsgstr \"在 %d 行解析 XML 错误：非法元素名称\"\n\n#: src/ne_xml.c:499\nmsgid \"Unknown error\"\nmsgstr \"未知错误\"\n\n#: src/ne_xml.c:625\nmsgid \"Invalid Byte Order Mark\"\nmsgstr \"非法字节顺序标记(BOM)\"\n\n#: src/ne_xml.c:714\n#, c-format\nmsgid \"XML parse error at line %d: %s\"\nmsgstr \"在 %d 行解析 XML 错误: %s\"\n\n#: src/ne_xmlreq.c:38\n#, c-format\nmsgid \"Could not parse response: %s\"\nmsgstr \"不能解析响应：%s\"\n\n#, fuzzy, c-format\n#~ msgid \"%s hash failed for Digest challenge\"\n#~ msgstr \"在摘要挑战中的参数丢失\"\n\n#, c-format\n#~ msgid \"Server did not send certificate chain\"\n#~ msgstr \"服务器不能发送证书链\"\n\n#~ msgid \"Could not read interim response headers\"\n#~ msgstr \"不能读临时响应头\"\n\n#~ msgid \"Server certificate changed: connection intercepted?\"\n#~ msgstr \"服务器证书改变：是否被拦截攻击？\"\n\n#~ msgid \"SSL disabled due to library version mismatch\"\n#~ msgstr \"由于库版本不匹配，SSL 已经禁用\"\n"
  },
  {
    "path": "src/.gitignore",
    "content": "*.lo\n.libs\nMakefile\nlibneon.la\nlibneon.a\nneon_config.h\n*.diff\nc++.c\ncheckincl.c\n*.*.*\n*.out\n*log\n*.bb\n*.da\n*.bbg\n*.[is]\n*.gc*\nmktable\n"
  },
  {
    "path": "src/COPYING.LIB",
    "content": "\t\t  GNU LIBRARY GENERAL PUBLIC LICENSE\n\t\t       Version 2, June 1991\n\n Copyright (C) 1991 Free Software Foundation, Inc.\n 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n[This is the first released version of the library GPL.  It is\n numbered 2 because it goes with version 2 of the ordinary GPL.]\n\n\t\t\t    Preamble\n\n  The licenses for most software are designed to take away your\nfreedom to share and change it.  By contrast, the GNU General Public\nLicenses are intended to guarantee your freedom to share and change\nfree software--to make sure the software is free for all its users.\n\n  This license, the Library General Public License, applies to some\nspecially designated Free Software Foundation software, and to any\nother libraries whose authors decide to use it.  You can use it for\nyour libraries, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthis service if you wish), that you receive source code or can get it\nif you want it, that you can change the software or use pieces of it\nin new free programs; and that you know you can do these things.\n\n  To protect your rights, we need to make restrictions that forbid\nanyone to deny you these rights or to ask you to surrender the rights.\nThese restrictions translate to certain responsibilities for you if\nyou distribute copies of the library, or if you modify it.\n\n  For example, if you distribute copies of the library, whether gratis\nor for a fee, you must give the recipients all the rights that we gave\nyou.  You must make sure that they, too, receive or can get the source\ncode.  If you link a program with the library, you must provide\ncomplete object files to the recipients so that they can relink them\nwith the library, after making changes to the library and recompiling\nit.  And you must show them these terms so they know their rights.\n\n  Our method of protecting your rights has two steps: (1) copyright\nthe library, and (2) offer you this license which gives you legal\npermission to copy, distribute and/or modify the library.\n\n  Also, for each distributor's protection, we want to make certain\nthat everyone understands that there is no warranty for this free\nlibrary.  If the library is modified by someone else and passed on, we\nwant its recipients to know that what they have is not the original\nversion, so that any problems introduced by others will not reflect on\nthe original authors' reputations.\n\f\n  Finally, any free program is threatened constantly by software\npatents.  We wish to avoid the danger that companies distributing free\nsoftware will individually obtain patent licenses, thus in effect\ntransforming the program into proprietary software.  To prevent this,\nwe have made it clear that any patent must be licensed for everyone's\nfree use or not licensed at all.\n\n  Most GNU software, including some libraries, is covered by the ordinary\nGNU General Public License, which was designed for utility programs.  This\nlicense, the GNU Library General Public License, applies to certain\ndesignated libraries.  This license is quite different from the ordinary\none; be sure to read it in full, and don't assume that anything in it is\nthe same as in the ordinary license.\n\n  The reason we have a separate public license for some libraries is that\nthey blur the distinction we usually make between modifying or adding to a\nprogram and simply using it.  Linking a program with a library, without\nchanging the library, is in some sense simply using the library, and is\nanalogous to running a utility program or application program.  However, in\na textual and legal sense, the linked executable is a combined work, a\nderivative of the original library, and the ordinary General Public License\ntreats it as such.\n\n  Because of this blurred distinction, using the ordinary General\nPublic License for libraries did not effectively promote software\nsharing, because most developers did not use the libraries.  We\nconcluded that weaker conditions might promote sharing better.\n\n  However, unrestricted linking of non-free programs would deprive the\nusers of those programs of all benefit from the free status of the\nlibraries themselves.  This Library General Public License is intended to\npermit developers of non-free programs to use free libraries, while\npreserving your freedom as a user of such programs to change the free\nlibraries that are incorporated in them.  (We have not seen how to achieve\nthis as regards changes in header files, but we have achieved it as regards\nchanges in the actual functions of the Library.)  The hope is that this\nwill lead to faster development of free libraries.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.  Pay close attention to the difference between a\n\"work based on the library\" and a \"work that uses the library\".  The\nformer contains code derived from the library, while the latter only\nworks together with the library.\n\n  Note that it is possible for a library to be covered by the ordinary\nGeneral Public License rather than by this special one.\n\f\n\t\t  GNU LIBRARY GENERAL PUBLIC LICENSE\n   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n  0. This License Agreement applies to any software library which\ncontains a notice placed by the copyright holder or other authorized\nparty saying it may be distributed under the terms of this Library\nGeneral Public License (also called \"this License\").  Each licensee is\naddressed as \"you\".\n\n  A \"library\" means a collection of software functions and/or data\nprepared so as to be conveniently linked with application programs\n(which use some of those functions and data) to form executables.\n\n  The \"Library\", below, refers to any such software library or work\nwhich has been distributed under these terms.  A \"work based on the\nLibrary\" means either the Library or any derivative work under\ncopyright law: that is to say, a work containing the Library or a\nportion of it, either verbatim or with modifications and/or translated\nstraightforwardly into another language.  (Hereinafter, translation is\nincluded without limitation in the term \"modification\".)\n\n  \"Source code\" for a work means the preferred form of the work for\nmaking modifications to it.  For a library, complete source code means\nall the source code for all modules it contains, plus any associated\ninterface definition files, plus the scripts used to control compilation\nand installation of the library.\n\n  Activities other than copying, distribution and modification are not\ncovered by this License; they are outside its scope.  The act of\nrunning a program using the Library is not restricted, and output from\nsuch a program is covered only if its contents constitute a work based\non the Library (independent of the use of the Library in a tool for\nwriting it).  Whether that is true depends on what the Library does\nand what the program that uses the Library does.\n  \n  1. You may copy and distribute verbatim copies of the Library's\ncomplete source code as you receive it, in any medium, provided that\nyou conspicuously and appropriately publish on each copy an\nappropriate copyright notice and disclaimer of warranty; keep intact\nall the notices that refer to this License and to the absence of any\nwarranty; and distribute a copy of this License along with the\nLibrary.\n\n  You may charge a fee for the physical act of transferring a copy,\nand you may at your option offer warranty protection in exchange for a\nfee.\n\f\n  2. You may modify your copy or copies of the Library or any portion\nof it, thus forming a work based on the Library, and copy and\ndistribute such modifications or work under the terms of Section 1\nabove, provided that you also meet all of these conditions:\n\n    a) The modified work must itself be a software library.\n\n    b) You must cause the files modified to carry prominent notices\n    stating that you changed the files and the date of any change.\n\n    c) You must cause the whole of the work to be licensed at no\n    charge to all third parties under the terms of this License.\n\n    d) If a facility in the modified Library refers to a function or a\n    table of data to be supplied by an application program that uses\n    the facility, other than as an argument passed when the facility\n    is invoked, then you must make a good faith effort to ensure that,\n    in the event an application does not supply such function or\n    table, the facility still operates, and performs whatever part of\n    its purpose remains meaningful.\n\n    (For example, a function in a library to compute square roots has\n    a purpose that is entirely well-defined independent of the\n    application.  Therefore, Subsection 2d requires that any\n    application-supplied function or table used by this function must\n    be optional: if the application does not supply it, the square\n    root function must still compute square roots.)\n\nThese requirements apply to the modified work as a whole.  If\nidentifiable sections of that work are not derived from the Library,\nand can be reasonably considered independent and separate works in\nthemselves, then this License, and its terms, do not apply to those\nsections when you distribute them as separate works.  But when you\ndistribute the same sections as part of a whole which is a work based\non the Library, the distribution of the whole must be on the terms of\nthis License, whose permissions for other licensees extend to the\nentire whole, and thus to each and every part regardless of who wrote\nit.\n\nThus, it is not the intent of this section to claim rights or contest\nyour rights to work written entirely by you; rather, the intent is to\nexercise the right to control the distribution of derivative or\ncollective works based on the Library.\n\nIn addition, mere aggregation of another work not based on the Library\nwith the Library (or with a work based on the Library) on a volume of\na storage or distribution medium does not bring the other work under\nthe scope of this License.\n\n  3. You may opt to apply the terms of the ordinary GNU General Public\nLicense instead of this License to a given copy of the Library.  To do\nthis, you must alter all the notices that refer to this License, so\nthat they refer to the ordinary GNU General Public License, version 2,\ninstead of to this License.  (If a newer version than version 2 of the\nordinary GNU General Public License has appeared, then you can specify\nthat version instead if you wish.)  Do not make any other change in\nthese notices.\n\f\n  Once this change is made in a given copy, it is irreversible for\nthat copy, so the ordinary GNU General Public License applies to all\nsubsequent copies and derivative works made from that copy.\n\n  This option is useful when you wish to copy part of the code of\nthe Library into a program that is not a library.\n\n  4. You may copy and distribute the Library (or a portion or\nderivative of it, under Section 2) in object code or executable form\nunder the terms of Sections 1 and 2 above provided that you accompany\nit with the complete corresponding machine-readable source code, which\nmust be distributed under the terms of Sections 1 and 2 above on a\nmedium customarily used for software interchange.\n\n  If distribution of object code is made by offering access to copy\nfrom a designated place, then offering equivalent access to copy the\nsource code from the same place satisfies the requirement to\ndistribute the source code, even though third parties are not\ncompelled to copy the source along with the object code.\n\n  5. A program that contains no derivative of any portion of the\nLibrary, but is designed to work with the Library by being compiled or\nlinked with it, is called a \"work that uses the Library\".  Such a\nwork, in isolation, is not a derivative work of the Library, and\ntherefore falls outside the scope of this License.\n\n  However, linking a \"work that uses the Library\" with the Library\ncreates an executable that is a derivative of the Library (because it\ncontains portions of the Library), rather than a \"work that uses the\nlibrary\".  The executable is therefore covered by this License.\nSection 6 states terms for distribution of such executables.\n\n  When a \"work that uses the Library\" uses material from a header file\nthat is part of the Library, the object code for the work may be a\nderivative work of the Library even though the source code is not.\nWhether this is true is especially significant if the work can be\nlinked without the Library, or if the work is itself a library.  The\nthreshold for this to be true is not precisely defined by law.\n\n  If such an object file uses only numerical parameters, data\nstructure layouts and accessors, and small macros and small inline\nfunctions (ten lines or less in length), then the use of the object\nfile is unrestricted, regardless of whether it is legally a derivative\nwork.  (Executables containing this object code plus portions of the\nLibrary will still fall under Section 6.)\n\n  Otherwise, if the work is a derivative of the Library, you may\ndistribute the object code for the work under the terms of Section 6.\nAny executables containing that work also fall under Section 6,\nwhether or not they are linked directly with the Library itself.\n\f\n  6. As an exception to the Sections above, you may also compile or\nlink a \"work that uses the Library\" with the Library to produce a\nwork containing portions of the Library, and distribute that work\nunder terms of your choice, provided that the terms permit\nmodification of the work for the customer's own use and reverse\nengineering for debugging such modifications.\n\n  You must give prominent notice with each copy of the work that the\nLibrary is used in it and that the Library and its use are covered by\nthis License.  You must supply a copy of this License.  If the work\nduring execution displays copyright notices, you must include the\ncopyright notice for the Library among them, as well as a reference\ndirecting the user to the copy of this License.  Also, you must do one\nof these things:\n\n    a) Accompany the work with the complete corresponding\n    machine-readable source code for the Library including whatever\n    changes were used in the work (which must be distributed under\n    Sections 1 and 2 above); and, if the work is an executable linked\n    with the Library, with the complete machine-readable \"work that\n    uses the Library\", as object code and/or source code, so that the\n    user can modify the Library and then relink to produce a modified\n    executable containing the modified Library.  (It is understood\n    that the user who changes the contents of definitions files in the\n    Library will not necessarily be able to recompile the application\n    to use the modified definitions.)\n\n    b) Accompany the work with a written offer, valid for at\n    least three years, to give the same user the materials\n    specified in Subsection 6a, above, for a charge no more\n    than the cost of performing this distribution.\n\n    c) If distribution of the work is made by offering access to copy\n    from a designated place, offer equivalent access to copy the above\n    specified materials from the same place.\n\n    d) Verify that the user has already received a copy of these\n    materials or that you have already sent this user a copy.\n\n  For an executable, the required form of the \"work that uses the\nLibrary\" must include any data and utility programs needed for\nreproducing the executable from it.  However, as a special exception,\nthe source code distributed need not include anything that is normally\ndistributed (in either source or binary form) with the major\ncomponents (compiler, kernel, and so on) of the operating system on\nwhich the executable runs, unless that component itself accompanies\nthe executable.\n\n  It may happen that this requirement contradicts the license\nrestrictions of other proprietary libraries that do not normally\naccompany the operating system.  Such a contradiction means you cannot\nuse both them and the Library together in an executable that you\ndistribute.\n\f\n  7. You may place library facilities that are a work based on the\nLibrary side-by-side in a single library together with other library\nfacilities not covered by this License, and distribute such a combined\nlibrary, provided that the separate distribution of the work based on\nthe Library and of the other library facilities is otherwise\npermitted, and provided that you do these two things:\n\n    a) Accompany the combined library with a copy of the same work\n    based on the Library, uncombined with any other library\n    facilities.  This must be distributed under the terms of the\n    Sections above.\n\n    b) Give prominent notice with the combined library of the fact\n    that part of it is a work based on the Library, and explaining\n    where to find the accompanying uncombined form of the same work.\n\n  8. You may not copy, modify, sublicense, link with, or distribute\nthe Library except as expressly provided under this License.  Any\nattempt otherwise to copy, modify, sublicense, link with, or\ndistribute the Library is void, and will automatically terminate your\nrights under this License.  However, parties who have received copies,\nor rights, from you under this License will not have their licenses\nterminated so long as such parties remain in full compliance.\n\n  9. You are not required to accept this License, since you have not\nsigned it.  However, nothing else grants you permission to modify or\ndistribute the Library or its derivative works.  These actions are\nprohibited by law if you do not accept this License.  Therefore, by\nmodifying or distributing the Library (or any work based on the\nLibrary), you indicate your acceptance of this License to do so, and\nall its terms and conditions for copying, distributing or modifying\nthe Library or works based on it.\n\n  10. Each time you redistribute the Library (or any work based on the\nLibrary), the recipient automatically receives a license from the\noriginal licensor to copy, distribute, link with or modify the Library\nsubject to these terms and conditions.  You may not impose any further\nrestrictions on the recipients' exercise of the rights granted herein.\nYou are not responsible for enforcing compliance by third parties to\nthis License.\n\f\n  11. If, as a consequence of a court judgment or allegation of patent\ninfringement or for any other reason (not limited to patent issues),\nconditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot\ndistribute so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you\nmay not distribute the Library at all.  For example, if a patent\nlicense would not permit royalty-free redistribution of the Library by\nall those who receive copies directly or indirectly through you, then\nthe only way you could satisfy both it and this License would be to\nrefrain entirely from distribution of the Library.\n\nIf any portion of this section is held invalid or unenforceable under any\nparticular circumstance, the balance of the section is intended to apply,\nand the section as a whole is intended to apply in other circumstances.\n\nIt is not the purpose of this section to induce you to infringe any\npatents or other property right claims or to contest validity of any\nsuch claims; this section has the sole purpose of protecting the\nintegrity of the free software distribution system which is\nimplemented by public license practices.  Many people have made\ngenerous contributions to the wide range of software distributed\nthrough that system in reliance on consistent application of that\nsystem; it is up to the author/donor to decide if he or she is willing\nto distribute software through any other system and a licensee cannot\nimpose that choice.\n\nThis section is intended to make thoroughly clear what is believed to\nbe a consequence of the rest of this License.\n\n  12. If the distribution and/or use of the Library is restricted in\ncertain countries either by patents or by copyrighted interfaces, the\noriginal copyright holder who places the Library under this License may add\nan explicit geographical distribution limitation excluding those countries,\nso that distribution is permitted only in or among countries not thus\nexcluded.  In such case, this License incorporates the limitation as if\nwritten in the body of this License.\n\n  13. The Free Software Foundation may publish revised and/or new\nversions of the Library General Public License from time to time.\nSuch new versions will be similar in spirit to the present version,\nbut may differ in detail to address new problems or concerns.\n\nEach version is given a distinguishing version number.  If the Library\nspecifies a version number of this License which applies to it and\n\"any later version\", you have the option of following the terms and\nconditions either of that version or of any later version published by\nthe Free Software Foundation.  If the Library does not specify a\nlicense version number, you may choose any version ever published by\nthe Free Software Foundation.\n\f\n  14. If you wish to incorporate parts of the Library into other free\nprograms whose distribution conditions are incompatible with these,\nwrite to the author to ask for permission.  For software which is\ncopyrighted by the Free Software Foundation, write to the Free\nSoftware Foundation; we sometimes make exceptions for this.  Our\ndecision will be guided by the two goals of preserving the free status\nof all derivatives of our free software and of promoting the sharing\nand reuse of software generally.\n\n\t\t\t    NO WARRANTY\n\n  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO\nWARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.\nEXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR\nOTHER PARTIES PROVIDE THE LIBRARY \"AS IS\" WITHOUT WARRANTY OF ANY\nKIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE\nLIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME\nTHE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN\nWRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY\nAND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU\nFOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR\nCONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE\nLIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING\nRENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A\nFAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF\nSUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH\nDAMAGES.\n\n\t\t     END OF TERMS AND CONDITIONS\n\f\n     Appendix: How to Apply These Terms to Your New Libraries\n\n  If you develop a new library, and you want it to be of the greatest\npossible use to the public, we recommend making it free software that\neveryone can redistribute and change.  You can do so by permitting\nredistribution under these terms (or, alternatively, under the terms of the\nordinary General Public License).\n\n  To apply these terms, attach the following notices to the library.  It is\nsafest to attach them to the start of each source file to most effectively\nconvey the exclusion of warranty; and each file should have at least the\n\"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the library's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This library is free software; you can redistribute it and/or\n    modify it under the terms of the GNU Library General Public\n    License as published by the Free Software Foundation; either\n    version 2 of the License, or (at your option) any later version.\n\n    This library is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n    Library General Public License for more details.\n\n    You should have received a copy of the GNU Library General Public\n    License along with this library; if not, write to the Free\n    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n    MA 02111-1307, USA\n\nAlso add information on how to contact you by electronic and paper mail.\n\nYou should also get your employer (if you work as a programmer) or your\nschool, if any, to sign a \"copyright disclaimer\" for the library, if\nnecessary.  Here is a sample; alter the names:\n\n  Yoyodyne, Inc., hereby disclaims all copyright interest in the\n  library `Frob' (a library for tweaking knobs) written by James Random Hacker.\n\n  <signature of Ty Coon>, 1 April 1990\n  Ty Coon, President of Vice\n\nThat's all there is to it!\n"
  },
  {
    "path": "src/ChangeLog",
    "content": "Sun Sep 12 19:21:30 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_locks.c (ne_lock_refresh): Fix to pass correct userdata to\n\tcallbacks, and do call lk_cdata.\n\nSun Sep 12 18:53:15 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* Makefile.in (libneon.a): Remove the archive first, avoiding\n\tstrange problems when build $(OBJECTS) change.\n\nSun Sep 12 18:40:50 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_utils.h: Add NE_FEATURE_SOCKS.\n\t\n\t* ne_utils.c (ne_has_support): Add NE_FEATURE_SOCKS.\n\t(version_string): Use NE_HAVE_SOCKS, add NE_HAVE_IDNA.\n\n\t* ne_socket.c (ne_sock_init): Use NE_HAVE_SOCKS.\n\nSun Sep 12 17:29:54 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_utils.c (version_string): Declare as array rather than\n\tpointer; include \"IPv6\" component as necessary\n\nSun Sep 12 15:51:38 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c (ne_iaddr_typeof): New function.\n\nSun Sep 12 12:00:10 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_defs.h (ne_attribute_malloc): New macro.\n\n\t* ne_alloc.h: Use it to avoid warnings with older GCCs.\n\nWed Aug 25 21:03:40 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_string.h (split_string, split_string_c, pair_string,\n\tsplit_string_free, pair_string_free): Remove obsolete interfaces.\n\nWed Aug 25 21:01:03 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_cookies.c, ne_cookies.h: Drop cookies support: used old spec\n\trevision and wasn't very complete anyway.\n\nWed Aug 25 20:40:26 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c: Remove ne_read, ne_write macros and just use recv\n\tand send; remove unused SOCK_ERR macro.\n\nWed Aug 25 20:27:43 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_xml.c (declare_nspaces): Drop rejection of names including a\n\tcolon to prevent breaking SVN deployments.\n\nWed Aug 25 19:45:20 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c (readable_raw): Use poll where available.\n\t(ne_sock_connect): Fail if not using poll and fd returned by\n\tsocket() is greater than FD_SETSIZE.\n\nWed Aug 25 18:40:28 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_xml.h (ne_xml_parse): Clarify that a len=0 call is required\n\tto signify end-of-document.\n\nWed Aug 25 18:37:13 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (resolve_first, resolve_next): New functions.\n\t(lookup_host): Use them to allow user-forced addresses.\n\n\t* ne_session.c (ne_set_addrlist): New function.\n\n\t* ne_private.h (struct ne_session_s): Add addrlist, numaddrs,\n\tcuraddr fields.\n\nWed Aug 25 18:25:31 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_xml.c (struct ne_xml_parser_s): Add bom_pos field.\n\t(ne_xml_parse): Skip over the UTF-8 Byte Order Mark since\n\tthe XML parsers do not support it yet.\n\nWed Jul  7 16:07:44 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (do_connect): Fix ne_conn_connected status call\n\t(Shameek Basu).\n\nMon Jul  5 18:40:35 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_basic.c (ne_content_type_handler): Use us-ascii as default\n\tcharset for text/xml, as per RFC3280.\n\nMon Jul  5 10:56:19 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_compress.c (struct ne_decompress_s): Add acceptor field.\n\t(gz_acceptor): New function.\n\t(ne_decompress_reader): Fix to pass the user-supplied userdata\n\tpointer to the user-supplied acceptor callback, via gz_acceptor.\n\nMon Jul  5 10:52:40 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_compress.c (do_inflate): Don't invoke the reader callback if\n\tno bytes where produced by inflate().\n\t(process_footer): Call the reader callback with size=0 to indicate\n\tend-of-response for a good checksum match.\n\nSat Jul  3 14:33:56 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_auth.c (auth_challenge): Fix to set got_qop in challenge\n\tcorrectly (Hideaki Takahashi).\n\nMon May 17 15:03:54 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.h (ne_addr_resolve): Clarify that 'flags' must\n\tbe passed as zero for forwards-compat.\n\nSun May  2 21:14:14 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\tFix buffer overflow in RFC1036 date parser, CVE CAN-2004-0389.\n\t\n\t* ne_dates.c (RFC1036_FORMAT): Specify maximum field with for day\n\tname.\n\t(ne_rfc1123_parse, ne_rfc1036_parse, ne_asctime_parse): Make\n\tthread-safe; remove static buffers.\n\nSun May  2 16:59:39 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_dates.c [RFC1123_TEST] (main): Remove embedded test cases.\n\nSun May  2 13:18:29 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* Makefile.in (LINK): Add -no-undefined.\n\nFri Apr 16 22:53:59 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_xml.c (declare_nspaces, expand_qname): Don't try to include\n\tdocument context in error strings.\t\n\nFri Apr 16 11:44:34 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* Makefile.in (LIBS): Include NEON_LTLIBS.\n\nWed Apr 14 10:39:53 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\tFix format string vulnerabilities, CVE CAN-2004-0179:\n\t\n\t* ne_207.c (ne_simple_request): Avoid format string\n\tvulnerabilities.\n\n\t* ne_xml.c (ne_xml_set_error): Likewise.\n\n\t* ne_props.c (propfind): Likewise.\n\n\t* ne_locks.c (ne_lock, ne_lock_refresh): Likewise.\n\nWed Apr 14 10:33:46 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_auth.c (ah_post_send): Avoid false positives from gcc\n\t-Wformat-security.\n\nTue Apr 13 20:51:41 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_auth.c: Conditionally include gssapi_generic.h.\n\nThu Apr  8 13:40:03 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_props.h: Don't use an anonymous enum for the proppatch\n\toperation type, as some C++ compilers don't like it.\n\nWed Apr  7 13:50:10 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (add_fixed_headers): Don't both sending Keep-Alive\n\theader if persistent connections are disabled.\n\nWed Apr  7 13:47:46 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_auth.c (auth_challenge): Allow Negotiate challenges from\n\ta proxy.\n\nWed Apr  7 13:36:55 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_auth.c (clean_session): Remove redundant assignment of\n\tGSS_C_NO_CONTEXT; gss_delete_sec_context already does this.\n\nWed Apr  7 13:33:10 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_auth.c (get_gss_name): Handle failure case internally.\n\t(auth_register): Updated accordingly.\n\nWed Apr  7 13:15:57 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c: Use strtoq to print off_t's where necessary.\n\nWed Apr  7 11:14:24 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_auth.c (get_gss_name): Take a hostname string.\n\t(auth_register): Pass proxy or server hostname to get_gss_name as\n\tappropriate.\n\nWed Apr  7 11:09:50 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_auth.c (continue_negotiate): If given no input token, and the\n\tgssctx is not in the initial state, reset it.\n\nMon Mar 29 17:06:49 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_auth.c: Adjust to cope with GSSAPI continuation:\n\t(struct auth_session_s): Store GSSAPI context, name and mechanism.\n\t(get_gss_name): Take an ne_session.\n\t(continue_negotiate): Renamed from gssapi_challenge; take input\n\ttoken, handle GSS_S_CONTINUE_NEEDED return value.\n\t(verify_digest_response): Renamed from verify_response.\n\t(verify_negotiate_response): New function.\n\t(auth_challenge): Cope with Negotiate responses which gratuitously\n\tbreak the auth-param grammar.\n\t(ah_post_send): Handle Negotiate responses.\n\t(free_auth, clean_session): Free persisted GSSAPI objects.\n\t(auth_register): Initialize GSSAPI objects.\n\nSun Mar 28 03:03:17 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_auth.c (get_gss_name): Don't leak token.value.\n\nSun Mar 28 02:59:58 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_auth.c (get_cnonce): Only use RAND_pseudo_bytes() if the PRNG\n\tis seeded.\n\nSun Mar 28 02:47:20 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_auth.c (gssapi_challenge, get_gss_name): Simplify.\n\nSun Mar 28 02:35:48 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_auth.c (request_gssapi, get_gss_name, auth_challenge):\n\tImplement the Negotiate protocol rather than the obsoleted\n\tGSS-Negotiate.\n\t(make_gss_error): New function.\n\t(gssapi_challenge): Use it for better error handling (set session\n\terror string); fix memory leaks.  Don't delegate credentials.\n\nSat Mar 27 20:49:24 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_auth.c (ah_post_send): Clear auth header collector buffers\n\tafter each request.\n\nFri Mar 26 12:16:15 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c (init_ssl): Just initialize the SSL library; delay\n\tseeding PRNG until really necessary (performance fix).\n\t(seed_ssl_prng): Split from init_ssl.\n\t(ne_sock_connect_ssl): Call seed_ssl_prng().\n\t(ne_sock_init): Adjust since init_ssl() can't fail.\n\nFri Mar 26 12:01:38 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_utils.c: Include zlib.h before ne_*.h to fix issues\n\ton platforms where zconf.h does \"#define const\".\n\nThu Mar 11 23:38:01 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_openssl.c (provide_client_cert): Avoid malloc(0) when server\n\tsends no CA names in CertificateRequest.\n\t(ne_ssl_cert_write): Be paranoid and clear the OpenSSL error stack\n\ton write failures.\n\nSun Mar  7 11:17:04 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* Makefile.in (CFLAGS): Don't use NEON_CFLAGS.\n\nMon Feb 23 23:03:08 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_string.c (ne_vsnprintf, ne_snprintf): New functions.\n\nSun Feb 22 23:34:47 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_private.h (struct ne_session_s): Remove expect100_works field.\n\n\t* ne_request.c (ne_set_request_expect100): New function.\n\t(ne_begin_request): Remove req->use_expect100 manipulation.\n\t(send_request): Handle enabling 100continue without a request\n\tbody.\n\n\t* ne_session.c (ne_set_expect100): Removed function.\n\nSun Feb 22 20:17:04 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c (error_ossl): Check for ERR_reason_error_string\n\treturning NULL.\n\nSun Feb 22 17:54:43 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c: Don't disable getaddrinfo support here.\n\nSun Feb 22 17:40:07 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_utils.h (min): Remove definition to...\n\n\t* ne_uri.c (min): ...here.\n\nSun Feb 22 17:31:35 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_props.h: Give the 'type' enum a tag name. \n\nSun Feb 22 17:27:28 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_207.c (end_element): Strip whitespace from cdata.\n\nSun Feb 22 16:27:58 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_auth.c (struct auth_request): Make auth_hdr, auth_info_hdr\n\tfields into ne_buffer *'s.\n\t(ah_collect_header): New function.\n\t(ah_create): Create ne_buffers for auth_{,info_}hdr; use\n\tah_collect_header rather than ne_duplicate_header to fix handling\n\tof multiple auth challenge headers.\n\t(ah_post_send): Adjust for char * -> ne_buffer *.\n\t(tokenize): Recognize a challenge scheme which is terminated with\n\ta comma (i.e. with no challange parameters).\n\t(auth_challenge): Fix handling of unrecognized challenges.\n\t(ah_destroy): Destroy ne_buffers.\n\nSun Feb 22 15:04:46 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (ne_set_request_body_provider64): New function.\n\nSun Feb 15 13:37:03 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_ssl.h: Define that ne_ssl_readable_dname returns UTF-8\n\tencoded strings.\n\n\t* ne_openssl.c (ne_ssl_readable_dname): Convert dname strings to\n\tUTF-8, or use \"???\".\n\nSat Feb 14 21:57:25 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_xml.c (invalid_ncname_ch1): New macro.\n\t(declare_nspaces): Use it, to reject some more invalid namespace\n\tprefixes; also check for a colon anywhere in the NCName.\n\t(expand_qname): Likewise for the element name.\n\nMon Feb  9 21:38:03 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_dates.c [WIN32] (GMTOFF): Use gmt_to_local_win32;\n\t(gmt_to_local_win32): New function, from Jiang Lei.\n\nMon Jan 26 14:38:05 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c (ne_sock_connect_ssl): Check that OpenSSL version\n\tmatches between library at run-time and headers at compile-time.\n\nSat Jan 24 17:49:27 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_dates.c (HAVE_STRUCT_TM___TM_GMTOFF): Alternative GMTOFF()\n\tmacro.\n\nSat Jan 24 16:49:30 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_auth.c (basic_challenge): Cast first parameter to ne_base64\n\tto unsigned char * to fix warnings with some compilers.\n\nSat Jan  3 13:17:36 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.h (ne_set_request_body_fd64): Define conditional on\n\tNE_LFS.\n\n\t* ne_request.c (ne_set_request_body_fd64): Likewise.\n\nThu Jan  1 18:01:45 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c: Use NE_HAVE_LFS not _LARGEFILE64_SOURCE in\n\tconditional support for off64_t.\n\nThu Jan  1 17:38:55 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.h [_LARGEFILE64_SOURCE] (ne_set_request_body_fd64):\n\tNew function.\n\t\n\t* ne_request.c: Define ne_lseek, ne_off_t, ne_strtoff,\n\tNE_OFFT_MAX, FMT_NE_OFF_T appropriately for _LARGEFILE64_SOURCE or\n\totherwise.\n\t(struct ne_request_s): Use ne_off_t in place of off_t throughout.\n\t(body_fd_send): Use ne_lseek; reset 'remain' after seeking.\n\t(clength_hdr_handler): Use ne_off_t, ne_strtoff and NE_OFFT_MAX.\n\t(set_body_length): Take an ne_off_t length parameter; use\n\tFMT_NE_OFF_T to print it.\n\t(ne_set_request_body_fd64): New function.\n\n\t* ne_utils.h (NE_FEATURE_LFS): New feature.\n\n\t* ne_utils.c (ne_has_support): Support NE_FEATURE_LFS.\n\nMon Nov 24 20:13:14 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (struct ne_response): Split handling for chunked vs\n\tclength-delimited responses into a union.  Use off_t for storing\n\twhole-length-of-response values.\n\t(read_response_block, ne_read_response_block): Update accordingly.\n\t(ne_begin_request): Remove unnecessary variable assignments.\n\nSun Nov 23 16:03:22 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.h (ne_set_request_body_fd): Take offset and length\n\targuments, return void.\n\t(ne_set_request_body_provider): Take off_t length argument.\n\n\t* ne_request.c (struct ne_request_s): Store current position\n\twithin buffer/file used as request body source.  Store request\n\tbody lengths using off_t type.\n\t(body_string_send): Adjust for renamed fields.\n\t(body_fd_send): Seek to requested offset; don't read past\n\trequested body length.\n\t(set_body_length): Renamed from set_body_size.\n\n\t* ne_basic.c (ne_put): Determine file size here; adjust for new\n\tne_set_request_body_fd API.\n\nSun Nov 23 15:05:12 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_basic.c, ne_basic.h: Remove two-functions-in-one,\n\tne_put_if_unmodified.\n\nFri Nov 14 14:05:32 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_utils.c (ne_has_support): Add NE_FEATURE_IDNA.\n\nFri Nov 14 13:11:49 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.c (set_hostinfo): [NE_HAVE_LIBIDN]: Use string from\n\tIDNA ToAscii operation on provided hostname if successful.\n\nFri Nov 14 11:23:16 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\tAll files: replace use of NEON_NODAV with NE_HAVE_DAV, NEON_SSL\n\twith NE_HAVE_SSL, NEON_ZLIB with NE_HAVE_ZLIB.  Use NE_HAVE_DAV\n\tnot USE_DAV_LOCKS.\n\n\t* ne_utils.c (ne_has_support): New feature detection interface,\n\treplaces ne_supports_ssl.\n\nThu Nov 13 20:38:28 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (ne_begin_request): Presume a 205 response has no\n\tmessage-body too; RFC2616 compliance fix.\n\nThu Nov 13 20:31:07 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_auth.c (ah_post_send): Treat a 401 response to a CONNECT\n\trequest as a valid proxy auth challenge, to work around buggy\n\tproxies.\n\nTue Nov 11 21:13:18 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\tPlace library-internal symbols in the \"ne__\" namespace.\n\t\n\t* ne_request.c (ne__pull_request_body): Renamed from\n\tne_pull_request_body; all callers updated.\n\n\t* ne_session.c (ne__negotiate_ssl): Renamed from\n\tne_negotiate_ssl; all callers updated.\n\nTue Nov 11 21:08:54 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_alloc.h: Mark all allocation functions as having 'malloc'\n\tattribute for GCC.\n\nTue Nov 11 20:36:12 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_xml.h (ne_xml_failure): Replaces ne_xml_valid,\n\tinverted and more useful return value.\n\n\t* ne_xml.c (struct ne_xml_parser_s): Replace 'valid' field with\n\t'failure', with inverted logic.\n\t(start_element, end_element, char_data): Check failure flag\n\tappropriately.  Set failure flag to return value of callback.\n\tSet failure flag to positive integer on a parse error.\n\t(ne_xml_create): Don't initialize failure flag.\n\t(ne_xml_parse): Check/set failure flag appropriately.\n\t(sax_error): Only set an error string (and the error flag)\n\tif failure is zero.\n\n\t* ne_207.c (ne_simple_request): Adjust to use ne_xml_failure.\n\n\t* ne_locks.c (ne_lock, ne_lock_refresh): Likewise.\n\n\t* ne_props.c (propfind): Likewise.\t\n\nWed Oct 22 22:19:19 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (read_response_block): Treat an EOF without clean\n\tSSL closure as a valid request body delimiter in any case.\n\nWed Oct 22 21:44:48 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_defs.h (ne_attribute): New macro.\n\n\t* ne_request.h, ne_session.h, ne_utils.h: Use ne_attribute instead\n\tof littering #ifdef __GNUC__ and __attribute__ everywhere.\n\nTue Oct 21 20:03:47 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\tFix various strict signedness bugs:\n\t\n\t* ne_auth.c (auth_session): Make nonce_count argument unsigned.\n\t(get_cnonce): Use unsigned data buffer.\n\t(get_gss_name, gssapi_challenge): Use unsigned integers for status\n\tvariables.\n\t(request_digest): Print nonce count as unsigned.\n\t(verify_response): Make nonce_count unsigned.\n\nTue Oct  7 20:52:06 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\tWhen using SSL via a proxy, don't leak server auth credentials to\n\tthe proxy, and vice versa.\n\t\n\t* ne_auth.c (auth_session): Add context field.\n\t(ah_create): Ignore challenges in a bad context.\n\t(ah_pre_send, ah_destroy): Check that the request-private cookie\n\tis not NULL.\n\t(auth_register): Take an isproxy flag; set context field\n\tappropriately in session structure.\n\t(ne_set_server_auth, ne_set_proxy_auth): Adjust accordingly.\n\nTue Oct  7 19:58:52 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_openssl.c (ne_negotiate_ssl): If the returned cert chain was\n\tNULL, try and create one from the peer certificate alone (fix for\n\tuse of SSLv2 connections).\n\nMon Sep 29 21:57:40 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_auth.c [WIN32]: Include windows.h to fix non-SSL build.\n\nThu Sep 25 20:05:18 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_xml.c (ne_xml_create): Specify an initial error string.\n\nSun Sep 21 23:00:10 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_cookies.c (set_cookie_hdl): Strip whitespace around cookie\n\tname and value.\n\nSun Sep 14 10:50:01 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c (ne_addr_resolve): Use result of autoconf test for\n\tworking AI_ADDRCONFIG support.\n\nSat Sep  6 12:05:00 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_openssl.c (check_identity): Take an optional server address\n\targument; check identity against IPaddress extension too if given.\n\t(check_certificate): Optionally pass server address to\n\tcheck_identity.\n\t(populate_cert): Adjust accordingly.\n\nThu Sep  4 21:41:38 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c (ne_sock_init): Succeed even if PRNG was not seeded.\n\nThu Sep  4 21:33:34 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.c (ne_set_useragent): Build and store the entire\n\tUser-Agent header field in sess->user_agent.\n\n\t* ne_request.c (add_fixed_headers): Adjust accordingly; avoid\n\tunnecessary calls to ne_buffer_*.\t\n\nThu Sep  4 21:27:34 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c: Include netinet/tcp.h.\n\t(ne_sock_connect): Disable the Nagle algorithm; thanks to Jim\n\tWhitehead and Teng Xu for the analysis.\n\nThu Sep  4 11:24:04 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_defs.h: Define ssize_t here for Win32.\n\n\t* ne_socket.h: Don't define ssize_t here.\n\nTue Sep  2 20:20:16 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_auth.c (auth_challenge): Update to use ne_token not\n\tsplit_string, patch by Tom Lee <i_am_gnomey@hotmail.com>.\n\nWed Jul 30 21:54:38 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_cookies.c (set_cookie_hdl): Fix NULL pointer dereference;\n\tthanks to Markus Mueller <markus-m.mueller@ubs.com>.\n\nFri Jul 25 11:05:52 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (do_connect): On failure to connect, set error\n\tstring and call ne_sock_close directly rather than using\n\taborted(); fix leak of socket structure.\n\nWed Jul 23 23:20:42 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\tFix SEGV if inflateInit2 fails with Z_MEM_ERROR etc.\t\n\t\n\t* ne_compress.c (set_zlib_error): New function.\n\t(do_inflate, gz_reader): Use it.\n\nWed Jul 23 22:50:50 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\tAdd support for GSS-Negotiate; patch from Risko Gergely and Burjan\n\tGabor:\n\n\t* ne_auth.c [HAVE_GSSAPI]: Include gssapi.h.\n\t(auth_scheme): Add auth_scheme_gssapi.\n\t(auth_session): Add gssapi_token.\n\t(clean_session): Free gssapi_token.\n\t(request_gssapi, get_gss_name, gssapi_challenge): New functions.\n\t(tokenize): Handle challenge with single token.\n\t(auth_challenge): Accept and process a GSS-Negotiate challenge.\n\t(ah_pre_send): Send GSS-Negotiate handshake.\n\nWed Jul 23 22:46:28 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_207.c (ne_207_set_response_handlers,\n\tne_207_set_propstat_handlers): Fix to match declarations (thanks\n\tto Diego Trtara).\n\nFri Jun 27 20:30:45 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_openssl.c [OPENSSL_VERSION_NUMBER < 0x0090700fL]:\n\tFix build against OpenSSL < 0.9.7.\n\nSun Jun 22 23:07:45 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.c (ne_session_destroy): Replace unnecessary use of\n\tNE_FREE with ne_free.\n\t(set_hostinfo): Don't free hostport/hostinfo here.\n\t(ne_session_proxy): Free existing proxy hostname here if\n\tnecessary.\n\nSat Jun 21 12:58:25 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (ne_begin_request): Set or clear is_http11 flag\n\tfor each request.\n\nWed Jun 18 20:54:44 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c: Add AI_ADDRCONFIG support;\n\t[USE_CHECK_IPV6]: Define only if __linux__.\n\t(init_ipv6) [USE_CHECK_IPV6]: New conditional.\n\t(ne_addr_resolve) [USE_ADDRCONFIG]: Use AI_ADDRCONFIG.\n\nWed Jun 18 20:03:13 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c (ne_sock_create): New function (renamed from\n\tcreate_sock).\n\t(ne_sock_connect): Take an ne_socket *, return int.\n\t(ne_sock_accept): Likewise.\n\t(ne_sock_close): Only call ne_close if fd is non-negative.\n\n\t* ne_request.c (aborted): Handle NE_SOCK_* errors specially.\n\t(do_connect): Adapt for ne_sock_create/connect interface.  Set\n\tsess->connected here on success.\n\t(open_connection): Don't set sess->connected here.\n\nSun Jun 15 12:14:22 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_ssl.h (ne_ssl_cert_digest): Pass digest as a pointer rather\n\tthan an array.\n\nSun Jun 15 11:00:09 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_stubssl.c (ne_ssl_cert_cmp): Add stub.\n\nWed May 28 21:37:27 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_openssl.c (ne_ssl_context_create): Enable workarounds in\n\tOpenSSL for better interop with buggy SSL servers.\n\nFri May 23 23:13:30 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_stubssl.c (ne_ssl_set_clicert): Add stub.\n\nSat May 10 17:05:26 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_xml.c: Rename struct ne_xml_handler to struct handler.\n\nThu May  8 20:55:46 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_openssl.c (ne_ssl_clicert_read): Pass \"b\" to fopen.\n\nTue May  6 22:08:08 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_openssl.c (check_certificate): Re-order verify failure\n\thandling to allow caller to set a custom session error string.\n\nTue May  6 20:21:27 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_md5.c (md5_stream): Restore.\n\nSat Apr 26 19:21:03 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (te_hdr_handler): Treat presence of any T-E\n\tresponse header as implying the response is chunked, regardless of\n\tvalue.\n\nSat Apr 26 18:11:24 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_xml.c: Rename struct ne_xml_nspace to struct namespace.\n\nWed Apr 23 22:19:29 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_openssl.c (ne_ssl_cert_export): Don't bother checking for\n\ti2d_X509() failure; no OpenSSL code ever checks, so everyone's\n\tdoomed if it really can fail.\n\nWed Apr 23 22:01:23 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_openssl.c (ne_ssl_cert_import, ne_ssl_cert_export,\n\tne_ssl_cert_write): Clear OpenSSL error stack on errors.\n\nWed Apr 23 18:23:53 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_stubssl.c (ne_ssl_cert_write, ne_ssl_cert_import,\n\tne_ssl_cert_export): Add stubs.\n\nWed Apr 23 14:05:32 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_openssl.c (ne_ssl_cert_write): New function.\n\nTue Apr 22 23:21:22 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_string.c (ne_unbase64): Optimise out some redundant branches.\n\nTue Apr 22 20:24:44 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_openssl.c (ne_ssl_cert_export, ne_ssl_cert_import,\n\tne_ssl_cert_cmp): New functions.\n\nTue Apr 22 18:31:55 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_string.c (ne_unbase64): New function.\n\nTue Apr 22 15:53:41 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_string.c (ne_base64): Fix encoding binary data; take unsigned\n\targument.\n\nTue Apr 22 13:07:48 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_stubssl.c (ne_ssl_cert_validity): Add stub.\n\nTue Apr 22 09:22:26 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_openssl.c (ne_ssl_cert_validity): New function.\n\t(asn1time_to_string): Format into a fixed-size buffer.\n\nTue Apr 22 08:38:30 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_locks.c (ne_lock_discover, ne_lock): Don't leak the cdata\n\tbuffer.\n\n\t* ne_props.c (ne_propfind_destroy): Don't leak the value buffer.\n\nMon Apr 21 23:52:25 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_xml.c (ne_xml_destroy): Free root element.\n\nMon Apr 21 23:46:17 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_openssl.c (dup_client_cert): Set decrypted state; dup the\n\tfriendly name.\n\t(ne_ssl_clicert_free): Free friendly name.\n\nMon Apr 21 19:44:55 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_md5.h (ne_md5_buffer, ne_md5_stream): Remove unused\n\tfunctions.\n\nMon Apr 21 18:17:14 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_locks.c, ne_207.c: s/NE_ELM_/ELM_/ since no element ids are\n\texported.\n\nMon Apr 21 16:38:14 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\tRedesign the XML interface: have startelm callback map {nspace,\n\tname} onto a state integer or decline.  Remove \"valid\"/\"invalid\";\n\tdon't abort the parse if no handler accepts an element.  Push\n\tcdata accumulation down into the caller; drop collect mode,\n\tstripws mode.\n\t\n\t* ne_xml.h (ne_xml_elmid, struct ne_xml_elm): Removed.\n\t(ne_xml_startelm_cb): Return a state/acceptance integer, take a\n\tstate integer, nspace, name and atts.\n\t(ne_xml_endelm_cb, ne_xml_cdata_cb): Take a state integer.\n\t(ne_xml_push_mixed_handler): Removed.\n\t(ne_xml_push_handler): Removed element list argument.\n\t(struct ne_xml_idmap, ne_xml_mapid): New interface.\n\n\t* ne_xml.c (struct element): Replaces ne_xml_state.  Add name,\n\tnspace, state fields.\n\t(friendly_name, find_handler, parse_element,\n\tne_xml_push_mixed_handler, push_handler): Removed functions.\n\t(declare_nspaces, expand_qname): Factored out from find_handler\n\tand parse_element.\n\t(start_element): Use expand_qname, declare_nspaces.  Find\n\tappropriate handler here.  Guarantee not to pass a NULL atts array\n\tto the start-element callback.  Drop collect mode.\n\t(end_element): Drop collect mode\n\t(ne_xml_push_handler): Fold push_handler back in.\n\t(ne_xml_mapid): New function.\n\n\t* ne_207.h (NE_ELM_*): Don't export element id.\n\t(NE_207_STATE_PROP, NE_207_STATE_TOP): Export state integers.\n\n\t* ne_207.c (struct ne_207_parser_s): Add cdata field.\n\t(map207): Replace element list with idmap array.\n\t(can_handle): New function, replacing check_context logic.\n\t(start_element): Determine new state integer; only accept the\n\telement in valid states.  Clear cdata.\n\t(end_element): Use state rather than element id.  Do nothing for\n\tend of 'response' element if element is incomplete.\n\t(ne_207_create): Create cdata buffer.\n\t(ne_207_destroy): Destroy cdata buffer.\n\t(ne_207_ignore_unknown): Removed function.\n\t(ne_simple_request): Don't call ne_207_ignore_unknown.\n\n\t* ne_props.h (NE_PROPS_STATE_TOP): Define state.\n\t\n\t* ne_props.c (struct ne_propfind_handler_s): Add value and depth\n\tfields.\n\t(ELM_flatprop): Define state.\n\t(flat_elms): Removed array.\n\t(chardata): Append to value field when in ELM_flatprop state.\n\t(startelm): Decline everything other than elements within the\n\t'prop' state.  Collect flatprop contents.\n\t(endelm): Collect flatprop contents.\n\n\t* ne_locks.c (struct discover_ctx, struct lock_ctx): Store cdata.\n\t(element_map): Replace element list with idmap array.\n\t(can_accept): Replaces check_context callback.\n\t(ld_startelm, lk_cdata, ld_cdata): New functions.\n\nMon Apr 14 00:04:20 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_207.h (ne_207_start_response, ne_207_end_response,\n\tne_207_start_propstat, ne_207_end_propstat): Use ANSI-style\n\tfunction pointers in typedefs.\n\n\t* ne_207.c (struct ne_207_parser_s): Updated accordingly.\n\nMon Apr 14 00:02:10 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (read_response_block): Better error messages for\n\tinvalid chunks, don't use strncmp for a two-character comparison.\n\nMon Apr  7 22:26:50 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_stubssl.c (ne_ssl_cert_identity): New function.\n\nMon Apr  7 22:16:16 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_openssl.c (struct ne_ssl_certificate_s): Add identity field.\n\t(check_identity): Add optional identity argument.\n\t(populate_cert): Retrieve cert identity using check_identity.\n\t(check_certificate): Pass extra NULL to check_identity.\n\t(ne_ssl_cert_identity): New function.\n\t(ne_ssl_cert_free): Free the identity field.\n\nMon Apr  7 21:29:54 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_openssl.c (check_identity): Take a string hostname rather\n\tthan a session object.\n\t(check_certificate): Adjust accordingly.\n\nSun Apr  6 21:26:05 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_string.h (NE_HEX2ASC): Cast result to char to avoid warnings\n\twith some compilers.\n \nSun Apr  6 20:11:42 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_openssl.c (ne_ssl_readable_dname): Include commonName or\n\temailAddress in returned string if either is the only attribute.\n\nSun Mar 30 10:54:20 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\tSplit decryption of client certs into two steps\n\t\n\t* ne_openssl.c (ne_ssl_clicert_encrypted, ne_ssl_clicert_decrypt):\n\tNew functions.\n\t(ne_ssl_client_cert_s): Add p12 and decrypted fields.\n\t(find_friendly_name): New function.\n\t(get_friendly_name): Removed function.\n\t(ne_ssl_clicert_read): Drop password callback; on decrypt failure,\n\textract friendly name and set decrypted state of clicert.\n\nSun Mar 30 10:54:01 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_stubssl.c (ne_ssl_clicert_encrypted, ne_ssl_clicert_decrypt):\n\tNew stubs.\n\t(ne_ssl_clicert_read): Adjusted for API change.\n\nSat Mar 29 14:23:37 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_openssl.c (ne_ssl_dname_cmp): New function.\n\n\t* ne_stubssl.c (ne_ssl_dname_cmp): New function.\n\nSat Mar 29 13:52:47 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_openssl.c (struct ne_ssl_client_cert_s): Add 'friendly_name'\n\tfield.\n\t(get_friendly_name, ne_ssl_clicert_name): New functions.\n\t(ne_ssl_clicert_read): Store the cert's friendly name.\n\n\t* ne_stubssl.c (ne_ssl_clicert_name): New function.\n\nSat Mar 29 13:16:14 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_openssl.c (ne_ssl_clicert_owner): New function.\n\nFri Mar 28 22:12:57 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_stubssl.c (ne_ssl_cert_digest): New function.\n\n\t* ne_openssl.c (ne_ssl_cert_digest): New function.\n\nWed Mar 26 20:41:57 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.c (ne_ssl_trust_cert) [NEON_SSL]: Only build when SSL\n\tsupport is present.\n\nWed Mar 26 20:01:00 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\tBegin abstraction of SSL layer to better isolate\n\tSSL-library-specific code, and to improve certificate handling\n\tinterface.\n\n\tDrop support for PEM-encoded client certificates.\n\n\t* ne_session.h (ne_ssl_trust_cert): Replaces ne_ssl_load_ca, in\n\tconjunction with ne_ssl_load_cert.\n\t(ne_ssl_trust_default_ca): Replaces ne_ssl_load_default_ca.\n\t(ne_ssl_keypw_prompt): Removed function, no longer needed.\n\t(ne_ssl_set_clicert): Replaces ne_ssl_load_pkcs12, in conjunction\n\twith ne_ssl_clicert_read.\n\t(ne_ssl_provide_clicert): Replaces ne_ssl_provide_ccert, callback\n\ttype changed.\n\t\n\t* ne_openssl.c: New file; much code moved from ne_session.c.\n\n\t* ne_privssl.h: New file, private interface between ne_socket.c\n\tand ne_openssl.c.\n\t\n\t* ne_ssl.h: New file.\n\n\t* ne_private.h (struct ne_session_s): Store pointers to\n\tne_ssl_client_cert etc opaque objects, not OpenSSL structures.\n\t\n\t* ne_session.c: Most of ne_ssl_* moved to ne_openssl.c.\n\t(ne_session_create, ne_session_destroy): Use ne_ssl_cert_* etc to\n\tmanage cert objects.\n\n\t* ne_socket.c (struct ne_socket_s): Replace SSL *, SSL_CTX *\n\tpointers with an ne_ssl_socket * pointer.\n\t(readable_ossl, error_ossl, read_ossl, write_ossl, ne_sock_close):\n\tCompensate for above change.\n\t(ne_sock_use_ssl): Removed function.\n\t(ne_sock_switch_ssl): Pass in SSL * as void for time being.\n\t(ne_sock_connect_ssl): Renamed and cleaned up version of\n\tne_sock_use_ssl_os.\n\t(ne_sock_sslsock): New function.\n\n\t* Makefile.in: Add deps for ne_openssl.c.\n\t\nSun Mar 23 13:02:58 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.c (ne_set_useragent): Use ne_malloc.\n\nSat Mar 22 21:06:45 2003  Joe Orton  <joe@manyfish.co.uk>\n\n     * ne_socket.c (raw_connect): Fill in sin6_family or sin_family\n     since AIX 4.3 fails to do so.\n\nWed Mar 19 20:44:11 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.c [NEON_SSL] (free_client_cert): Build conditional on\n\tNEON_SSL.\n\nMon Mar 17 20:33:32 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c: Include netdb.h conditional on HAVE_NETDB_H. (fix\n\tbuild for older versions of CygWin).\n\nSun Mar 16 23:30:20 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.c (check_identity): Fix leak of subject alt. name\n\tstructures.\n\nSun Mar 16 19:21:22 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.c (free_client_cert): New function.\n\t(ne_session_destroy, ne_ssl_load_pem, ne_ssl_load_pkcs12): Call\n\tit; prevent memory leak if ne_ssl_load_{pem,pkcs12} are called >1\n\tper session.\n\nSun Mar 16 18:00:34 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.c (provide_client_cert): Free peer certificate after\n\tuse.\n\t(ne_session_destroy): Free client cert and key if present.\n\nSun Mar 16 14:23:05 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_xml.c [HAVE_EXPAT]: Include xmlparse.h for bundled expat\n\tbuild.\n\n\t* ne_utils.c: Only include expat.h if HAVE_XMLPARSE_H is not\n\tdefined.\n\nWed Mar 12 15:04:13 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_redirect.c (struct redirect): Add 'valid' field.\n\t(post_send): Set and clear 'valid' to keep track of whether stored\n\tURI is valid.\n\t(ne_redirect_location): Return NULL if stored URI is not valid.\n\nWed Mar 12 14:52:49 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_uri.c (ne_uri_free): Zero-initialize structure after\n\tfree'ing.\n\nTue Mar 11 22:01:11 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_redirect.c (ne_redirect_location): Return NULL if no redirect\n\tsession is registered, rather than SEGV; Ralf Mattes\n\t<rm@fabula.de>.\n\nSun Mar  9 16:33:24 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\tFix a memory leak if an XML parse error occurs during a PROPFIND\n\tresponse:\n\t\n\t* ne_props.c (ne_propfind_current_private): Return NULL if no\n\tpropset is being processed.\n\t(free_propset): Free propset href here.\n\t(end_response): Don't free propset href here.  Set current field\n\tof handler to NULL after free'ing propset.\n\t(ne_propfind_destroy): Free current propset if one was being\n\tprocessed.\n\nSun Mar  9 11:53:58 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_207.c (ne_207_destroy): Fix possible leak of reason_phrase\n\tstring.\n\nSun Mar  9 11:01:15 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_utils.c (ne_parse_statusline): Use ne_strclean.\n\t\n\t* ne_session.c (ne_get_error): Use ne_strclean.\n\nSun Mar  9 10:53:52 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_xml.c: Remove broken \"UTF-8 decoding\" support used for libxml\n\t1.x.\n\nSun Mar  9 09:55:26 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_xml.c: Drop support for expat < 1.95.0 and libxml 1.x.\n\n\t* ne_utils.c (version_string): Include expat version string.\n\nSun Mar  9 09:54:00 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c: Don't declare h_errno on Win32 either.\n\nSun Mar  9 08:49:40 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_string.c (do_concat) [HAVE_STPCPY]: Use stpcpy rather than\n\tstrlen/memcpy, when available.\n\nMon Mar  3 22:17:04 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c [!USE_GETADDRINFO && !HAVE_DECL_H_ERRNO): Declare\n\th_errno (fix build on SCO OpenServer 5.0).\n\nSat Mar  1 21:22:19 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_redirect.c (free_redirect): Fix once-per-session memory leak.\n\nSat Mar  1 20:23:47 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\tAdd implemention of simple memory leak tracking, for testing\n\tpurposes.\n\n\t* ne_alloc.c [NEON_MEMLEAK] (tracking_malloc, ne_free_ml,\n\tne_malloc_ml, ne_calloc_ml, ne_realloc_ml, ne_strdup_ml,\n\tne_strndup_ml, ne_memleak_dump): New functions.\n\n\t* memleak.h: New header.\n\nSat Mar  1 13:44:26 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\tFirst step towards automated memory leak tests.\n\t\n\t* ne_alloc.c (ne_free): New function.\n\n\t* All files: replace use of free() with ne_free().\n\nSat Mar  1 09:48:39 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_uri.c (ne_path_unescape): Fix memory leak on invalid URI.\n\nSat Mar  1 08:03:18 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_string.c (ne_strclean): New function.\n\nWed Feb 26 21:45:12 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (ne_begin_request, proxy_tunnel, open_connection)\n\t[NEON_SSL] Don't build CONNECT tunnel support code if SSL is not\n\tsupported.\n\nWed Feb 26 21:44:18 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_utils.c (ne_debug_init): Allow ne_debug_init(NULL, 0) to turn\n\toff debugging.  Fix to produce debug output if the any of the\n\tspecified \"channels\" are active, not all.  (also fixing\n\tNE_DBG_FLUSH support).\n\nTue Feb 25 23:12:31 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_compress.c (process_footer): Mention number of extra bytes in\n\terror message for oversized footer.\n\nSun Feb 23 21:19:20 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_auth.c (verify_response): Fix to parse nonce count as hex\n\tstring rather than decimal; fix verification of >9 responses.\n\nThu Feb 13 20:35:45 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.c (ne_set_useragent): Fix to append \"neon/x.y.z\" to\n\tapplication-supplied token rather prepend.\n\nThu Feb 13 09:06:22 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (open_connection): Fix for CONNECT tunnelling\n\t(regression since 0.23.x), thanks to Nathan Hand\n\t<Nathan.Hand@defence.gov.au>.\n\nMon Feb  3 22:10:54 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\tImplement Daniel Stenberg's trick to avoid the slow AF_UNSPEC\n\tlookups on Linux:\n\t\n\t* ne_socket.c (init_ipv6, ipv6_disabled): New function and global.\n\t(ne_sock_init): Call init_ipv6.\n\t(ne_addr_resolve) [USE_GETADDRINFO]: Pass AF_INET in hints if\n\tipv6_disabled is set.\n\nMon Feb  3 20:55:47 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c [__hpux && USE_GETADDRINFO]: Undefine\n\tUSE_GETADDRINFO to work around broken implementation in HP-UX\n\t11.11.\n\nMon Jan 27 21:39:31 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c (write_raw): Fix for handling EINTR during write(),\n\tfrom Sergey N Ushakov.\n\nThu Jan 16 21:59:03 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\tAllow _init after _finish to succeed: Sergey N Ushakov.\n\t* ne_socket.c (init_result): New global variable.\n\t(ne_sock_init): Use init_result global rather than result.\n\t(ne_sock_finish): Clear init_result.\n\nFri Dec 27 17:03:17 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (build_request): Remove redundant call to\n\tne_buffer_clear.\n\nFri Dec 27 14:38:08 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (ne_request_create): strdup the method string.\n\t(ne_request_destroy): free the method.\n\nMon Dec 23 17:04:32 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c (ne_write, ne_read, ne_close, ne_errno): Renamed\n\tmacros from NEON_WRITE, NEON_READ, NEON_CLOSE, NEON_ERRNO.\n\tAll callers changed.\n\nMon Dec 23 16:58:43 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\tAdd proper Win32 socket error handling, merged efforts of Johan\n\tLindh and Sergey N Ushakov <ushakov@int.com.ru>:\n\t\n\t* ne_socket.c (ne_errno, NE_ISINTR, NE_ISRESET, NE_ISCLOSED): New\n\tmacros.\n\t[WIN32] (print_error): New function.\n\t(set_strerror) [WIN32]: Use print_error.\n\t(readable_raw, read_raw, write_raw): Use new error handling\n\tmacros.\n\t(ne_addr_resolve) [WIN32]: Use WSAGetLastError() rather than\n\th_errno.\n\t(ne_addr_error) [WIN32]: Use print_error.\n\nTue Dec 10 21:41:26 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c (ne_iaddr_print): Renamed from ne_addr_print for\n\tconsistency with other ne_iaddr_ functions.\n\nSun Dec  8 20:08:31 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_auth.c (get_cnonce): Use GetCurrentThreadId() on Win32.\n\nSun Nov 24 18:45:32 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_auth.c: Remove qop_values and algorithm_names arrays.\n\t(request_digest): Inlined qop, algorithm name lookups accordingly.\n\nSun Nov 24 16:45:39 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_auth.h: Renamed ne_request_auth typedef to ne_auth_creds.\n\n\t* ne_auth.c (auth_session): Renamed reqcreds, recreds_ud fields to\n\tcreds, userdata.\n\t(auth_register, ne_set_proxy_auth, ne_set_server_auth): Update for\n\tne_request_auth rename.\n\nFri Nov 22 17:39:35 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_auth.c (auth_challenge): Fix support for RFC2617-style digest\n\tauth; notice the qop= parameter in challenge.  Fix leak of parsed\n\tqop array.\n\nFri Nov 22 17:08:01 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_auth.c (get_cnonce): Rewrite to use either pseudo-random data\n\tfrom the SSL library (if available), or really-not-random data\n\tfrom gettimeofday/getpid otherwise.\n\nSun Nov 17 22:13:49 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c (ne_addr_print) [USE_GETADDRINFO]: Use the SACAST()\n\tmacro.\n\nSun Nov 17 19:29:23 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c (ne_sock_connect): Make address argument const.\n\t(raw_connect): Make address argument const; adjust to use a copy\n\tof the sockaddr structure, which is correct anyway.\n\t(ne_addr_first, ne_addr_next): Make return pointer const.\n\n\t* ne_private.h (struct host_info): Store current address as const.\n\nSun Nov 17 19:03:01 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c (ne_register_progress): Removed function.\n\n\t* ne_socket.h (ne_block_reader, ne_progress,\n\tne_register_progress): Removed.\n\n\t* ne_request.c (do_connect): Don't call ne_register_progress.\n\n\t* ne_request.h: Add ne_block_reader typedef.\n\n\t* ne_session.h: Include sys/types.h; add ne_progress typedef.\n\t\nSun Nov 17 18:59:29 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c (ne_iaddr_make, ne_iaddr_cmp, ne_iaddr_free):\n\tNew functions.\n\t\nMon Nov 11 19:51:24 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\tAllow discovery of document encoding.\n\t\n\t* ne_xml.c [HAVE_EXPAT]: (struct ne_xml_parser_s): Add encoding\n\tfield.  (decl_handler): New function.\n\t(ne_xml_doc_encoding): New function.\n\nMon Nov 11 19:48:43 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_xml.c (sax_handler): Use sax_error for fatal error callback.\n\nFri Oct 11 23:50:01 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_private.h (struct ne_session_s): Change 'connected' to be a\n\tsimple boolean flag.\n\n\t* ne_session.c (ne_close_connection): Treat 'connected' as a\n\tboolean.\n\n\t* ne_request.c (open_connection): Greatly simplified.\n\nFri Oct 11 00:46:52 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_props.c (end_propstat): Fix NULL pointer dereference\n\tif no status object is given.\n\nTue Oct  8 20:10:24 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_xml.c (ne_xml_create) [!HAVE_EXPAT]: Set 'replaceEntities'\n\tflag in created parser so that entities are dereferenced in\n\tattribute values.\n\nMon Oct  7 22:08:46 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c (init_ssl): Attempt to seed PRNG using EGD socket at\n\tpath EGD_PATH or a set of predetermined locations if EGD_PATH is\n\tnot defined.  No longer try $EGDSOCKET or $HOME/.entropy.\n\nMon Oct  7 21:32:33 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_auth.c (register_hooks): Removed function.\n\t(auth_register): Fold in register_hooks.\n\nTue Sep 24 21:24:44 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (ne_request_create): Pass Request-URI to\n\tcreate_request hooks.\n\nTue Sep 24 20:42:45 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c [__hpux]: Define _XOPEN_SOURCE_EXTENDED to 1, to\n\tpick up h_errno definition on HP-UX 10.20.\n\nWed Sep 18 21:46:28 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_compress.c (struct ne_decompress_s): Add zstrinit field.\n\t(gz_reader): Set zstrinit after inflateInit2 succeeds.\n\t(ne_decompress_destroy): Only call inflateEnd if zstrinit is set.\n\nWed Sep 18 19:56:00 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_auth.c: Remove incomplete domain support.\n\nTue Sep 17 21:05:11 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\tFix rejection of server certificates which have commonName as the\n\tleast specific attribute.\n\n\t* ne_session.c (check_identity): Don't ignore commonName if it is\n\tthe least specific attribute.\n\nTue Sep 10 21:08:18 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (lookup_host): Destroy cached address if resolve\n\tfails; fix segfault if a second request in the session is\n\tdispatched after the DNS lookup fails on the first.\n\nMon Sep  9 22:26:03 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (RETRY_RET): Treat SSL truncation as a legitimate\n\tpersistent connection timeout.\n\nFri Aug 30 21:58:45 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (read_response_block): Clear can_persist flag if an\n\tEOF was read (fix for read-till-EOF response terminated by an\n\tunclean SSL shutdown).\n\nMon Aug 26 18:05:00 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c: Fix HAVE_LIMITS check (Blair Zajac).\n\nSun Aug 25 23:29:06 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (do_connect): Add debug message for connection\n\tattempt.\n\nSun Aug 25 22:54:04 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.h (ne_addr_print): Make address argument const.\n\nSun Aug 25 11:52:32 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c (ne_addr_print): New function.\n\nSun Aug 25 10:09:10 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\tFix interop with Tomcat/3.2 SSL server, which performs an unclean\n\tshutdown on an HTTP/1.0 response without a C-L header.\n\n\t* ne_request.c (read_response_block): Ignore SSL connection\n\ttruncation for a read-till-EOF response, where no reseponse\n\tcontent has been read yet.\n\t(ne_read_response_block): Always increase 'total' counter.\n\nSun Aug 25 08:47:41 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (aborted): Handle code=0 case specifically, and\n\tNE_SOCK_* as default.\n\nSun Aug 25 08:24:48 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.h: Add `NE_SOCK_TRUNC' return value.\n\t\n\t* ne_socket.c (error_ossl): Return NE_SOCK_TRUNC when an EOF is\n\treceived without a close_notify.\n\nSat Aug 24 17:37:14 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.h (ne_inet_addr): New type.\n\t(ne_addr_first, ne_addr_next): New public interface.\n\t(ne_sock_connect): Change first parameter to ne_inet_addr.\n\n\t* ne_socket.c: Predefine ne_inet_addr for ne_socket.h, replacing\n\tne_raw_addr.\n\t(ne_addr_first, ne_addr_first): Renamed from addr_first,\n\taddr_next; return type now ne_inet_addr; made public.\n\t(ne_sock_connect): Fold in make_socket() macro; just connect to\n\tsingle IP address passed in.\n\n\t* ne_private.h (struct host_info): Renamed 'addr' to 'address',\n\tdded 'current' field, removed 'resolved' field.\n\n\t* ne_request.c (lookup_host): Adjust for addr->address rename.\n\t(ne_begin_request): Call lookup_host if 'address' is NULL in\n\thost_info structure, don't use 'resolved' flag.\n\t(do_connect): Replaces init_socket; factor more code out from\n\topen_connection.  Loop over available addresses until an\n\tne_sock_connect call succeeds.\n\t(open_connection): Moved code into do_connect.\n\n\t* ne_session.c (ne_session_destroy): Adjust for addr->address\n\trename.\n\nSat Aug 24 13:45:26 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_string.c (count_concat, do_concat): Compact into while()\n\tloops.\n\nSat Aug 24 13:36:04 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_private.h (VERSION_PRE11): Removed macro.\n\t(struct ne_session_s): Add is_http11 field; removed version_major,\n\tversion_minor fields.\n\n\t* ne_request.c (add_fixed_headers): Use is_http11 flag rather than\n\tVERSION_PRE11 macro.\n\t(ne_begin_request): Set and use is_http11 flag.\n\n\t* ne_session.c (ne_version_pre_http11): Use is_http11 flag.\n\t(ne_session_create): Don't set version_major, version_minor fields.\n\nSat Aug 24 09:00:13 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (struct ne_request_s): Removed abs_path field.\n\t(ne_set_request_uri): Removed function.\n\t(ne_request_create): Set req->uri to be the actual Request-URI.\n\tDon't use an absoluteURI in Request-URI if using SSL via a proxy\n\ttunnel, or if passed-in path does not begin with a '/'.\n\t(build_request): Use pre-determined Request-URI.\n\t(proxy_tunnel): Pass true Request-URI to ne_request_create.\n\t(ne_request_destroy): Don't free abs_path.\n\nSat Aug 24 00:37:25 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (aborted): Fix handling of _CLOSED and _TIMEOUT\n\tsocket errors, and of non-socket errors.  Presume ne_sock_error\n\tcannot return NULL.\n\nSat Aug 24 00:07:33 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_cookies.c (set_cookie_hdl): Ensure that each cookie field is\n\tsafe to free().\n\nFri Aug 23 23:46:58 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (aborted): Close the connection after setting the\n\tsession error, otherwise the socket error is lost.\n\nFri Aug 23 22:50:30 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c (ne_sock_init): Set SIGPIPE disposition before SSL\n\tlibrary initalization, so it happens even if SSL library\n\tinitialization fails.\n\nFri Aug 23 22:03:26 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c [USE_GETADDRINFO] (make_socket): Pass SOCK_STREAM to\n\tsocket() rather than ai_socktype: on RHL6.2, ai_socktype is\n\treturned as zero.\n\nWed Aug 21 18:06:36 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c: Reinstate stdlib.h include.\n\n\t* ne_socket.h: Reinstate sys/socket.h include.\n\nWed Aug 21 12:58:47 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c (ne_addr_resolve): Accept IPv6 addresses enclosed in\n\tsquare brackets.\n\nWed Aug 21 09:37:24 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_uri.c (ne_uri_parse): Parse literal IPv6 address using the\n\tRFC2732 `[address]' syntax.\n\nMon Aug 19 17:18:45 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c (ne_addr_error): Override a horribly generic error\n\tmessage from gai_strerror().\n\nMon Aug 19 16:24:37 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.h: Remove netinet/in.h etc includes.\n\t(ne_sock_addr): Add new opaque type.\n\t(ne_addr_resolve, ne_addr_result, ne_addr_error, ne_addr_destroy):\n\tNew functions.\n\t(ne_sock_connect): Changes address argument to `ne_sock_addr *'.\n\t(ne_name_lookup): Removed function.\n\n\t* ne_socket.c: Added netinet/in.h etc includes.\n\t(ne_sock_addr, ne_raw_addr): Define types.\n\t(make_socket): New macro.\n\t(ne_addr_resolve): Replace ne_name_lookup; store results (multiple\n\taddresses if returned) in returned ne_sock_addr object.  Use\n\tgetaddrinfo() if available.\n\t(raw_connect, addr_first, addr_next, ne_addr_result,\n\tne_addr_error, ne_addr_destroy): New functions.\n\t(ne_sock_connect): Re-implement to loop through available\n\taddresses until a connect() succeeds; use make_socket, raw_connect\n\tauxiliaries.\n\n\t* ne_private.h (struct host_info): Store an ne_sock_addr pointer.\n\n\t* ne_request.c (lookup_host): Use new ne_addr_* interface.\n\n\t* ne_session.c (ne_session_destroy): Destroy address objects.\n\t\nMon Aug 19 00:19:49 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c: Move prng_seeded inside ifdef NEON_SSL region to\n\tprevent unused variable warning for non-SSL build.\n\nSun Aug 18 23:21:21 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_string.h (ne_strerror): Return buffer.\n\nSun Aug 18 23:17:56 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c (set_error): Use ne_strnzcpy.\n\nSun Aug 18 23:14:07 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_string.c (ne_strerror): Use ne_strnzcpy.\n\nSun Aug 18 23:11:45 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_string.h (ne_strnzcpy): New macro.\n\nSun Aug 18 22:48:27 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c (ne_sock_init): Check directly for SIGPIPE\n\tdefinition rather than HAVE_SIGPIPE.\n\nSun Aug 18 13:49:49 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.c (set_hostport): Use %u for printing unsigned int.\n\nSun Aug 18 13:47:43 2002  Joe Orton  <joe@manyfish.co.uk>\n\t\n\t* ne_utils.h (NE_DBG_SSL): New constant.\n\n\t* ne_session.c [NEON_SSL] (everywhere): Use NE_DBG_SSL channel for\n\tdebugging messages.\n\nSun Aug 18 08:17:19 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.c (match_hostname): Fix to use case-insensitive\n\tstring comparison.\n\nSun Aug 18 08:10:12 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.c (check_identity): Check the commonName if no\n\talt. names of DNS type were found.\n\nSun Aug 18 07:39:35 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.c (check_identity): Use the most specific commonName\n\tattribute found, not the first.  (for RFC2818 compliance)\n\nSun Aug 18 01:54:53 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.c (match_hostname): Invert return value.\n\t(check_identity): New function; split out commonName check from\n\tcheck_certificate, check subjectAltName extension instead if\n\tpresent.\n\t(check_certificate): Use check_identity.\n\nSat Aug 17 19:59:21 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.c (check_certificate): Extend debugging code to dump\n\tthe whole certificate chain, but #if 0 it by default.\n\nMon Aug 12 12:04:51 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (aborted): Use NE_FMT_SSIZE_T to print ssize_t\n\tvalue.\n\nMon Aug 12 11:08:35 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\tSupport PRNG seeding via EGD to make SSL work on platforms which\n\tlack /dev/random:\n\n\t* ne_socket.c (init_ssl): New function.\n\t(ne_sock_init): Call init_ssl, set prng_seeded global on success.\n\t(ne_sock_use_ssl_os): Fail early if prng_seeded is not set, and\n\tRAND_status returns false.\n\nTue Aug  6 07:18:30 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c (ne_sock_use_ssl_os): Remove goto-based error\n\thandling.  Don't call SSL_shutdown after SSL_connect fails.\n\nMon Aug  5 23:18:55 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.c (ne_ssl_keypw_prompt): Don't set SSL_CTX default\n\tpassword callbacks, since these are never invoked.  Implement\n\tonce, stub for !NEON_SSL is no longer needed.\n\nMon Aug  5 21:01:54 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.c (ne_ssl_load_pem): Pass private key prompt callback\n\tto PEM_read_X509, PEM_read_PrivateKey (patch by Daniel Berlin).\n\tAlso handle errors properly; call ERR_get_error() to pop the\n\terrors of the error stack.\n\nMon Aug  5 20:15:10 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.c (provide_client_cert): Increase reference count on\n\tkey and certificate, to prevent them being free'd too early.\n\nSun Aug  4 22:35:27 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\tFix `retry_after_abort' test in request.c:\n\n\t* ne_request.c (send_request): Don't use the 'persisted' flag\n\tuntil after a new connection has been opened, when it may have\n\tbeen reset.\n\nSun Aug  4 17:26:37 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (struct ne_request_s): Remove reqbuf field.\n\t(ne_request_create, ne_request_destroy): Don't (de)allocate reqbuf.\n\t(build_request): Allocate the returned buffer internally.\n\t(ne_begin_request): Destroy the buffer after use.\n\nSun Aug  4 15:36:01 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.c (ne_ssl_load_pem): Close file after use.\n\nSun Aug  4 12:55:49 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\tFactor out EPIPE, ECONNRESET handling from write_raw:\n\t\n\t* ne_socket.c (MAP_ERR): New macro.\n\t(write_raw, error_ossl): Use MAP_ERR.\n\nSun Aug  4 12:25:34 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c (ne_sock_switch_ssl): New function.\n\nSun Aug  4 12:24:23 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c (ne_sock_switch_ssl): New function, really just for\n\ttest suite.\n\nSat Aug  3 22:11:33 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_auth.c (ne_forget_auth): Fix segfault if either server or\n\tproxy auth is not in use.\n\nSat Aug  3 22:06:32 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_redirect.c (create, post_send, ne_redirect_register,\n\tne_redirect_location): Updated for new hook interface.\n\nSat Aug  3 19:02:33 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\tAdjustment of hook interface and use: fixing a design flaw causing\n\ta segfault in the auth hooks when two requests are used\n\tconcurrently for a single session during a CONNECT tunnel.\n\t\n\t* ne_request.h, ne_session.h:\n\t(ne_get_request_private, ne_get_session_private): Replace\n\tne_request_hook_private, ne_session_hook_private.\n\t(ne_set_session_private, ne_set_request_private): Replace\n\tne_hook_session_accessor, ne_hook_request_accessor.\n\n\t* ne_request.h (ne_create_request_fn, ne_pre_send_fn,\n\tne_post_send_fn): Add ne_request pointer as first argument.\n\t(ne_hook_destroy_request): Take ne_destroy_req_fn function.\n\t(ne_hook_destroy_session): Take ne_destroy_sess_fn function.\n\t\n\t* ne_request.c (struct ne_request_s): Renamed `accessor_hooks'\n\tfield to `private'.\n\t(get_private): Renamed from call_access; don't invoke function.\n\t(ne_null_accessor): Removed function.\n\n\t* ne_auth.c (struct auth_class): Store hook id.\n\t(auth_session): Remove auth_request pointer.\n\t(ah_create): Store auth_request pointer as request-private data.\n\t(ah_pre_send, ah_post_send, ah_destroy): Retrieve auth_request\n\tpointer from request-private data.\n\t(register_hooks, ne_forget_auth): Use\n\tne_{get,set}_session_private.\n\n\t* ne_locks.c (struct lh_req_cookie): New structure.\n\t(struct ne_lock_store_s): Remove submit_locks field.\n\t(lk_create, lk_pre_send, submit_lock, ne_lock_using_resource,\n\tne_lock_using_parent, lk_destroy): Adjust to use lh_req_cookie\n\tpointer as request-private data.\n\n\t* ne_cookies.c (create, pre_send): Adjust for hook prototype\n\tchanges.\n\nWed Jul 31 23:46:17 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c [NEON_SSL]: Include limits.h for INT_MAX definition.\n\nMon Jul 29 20:55:57 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_auth.c (struct auth_class): New structure; abstracts out\n\tproxy/server generic auth handling more cleanly.\n\t(ah_server_class, ah_proxy_class): Declare variables.\n\t(auth_session): Reference an auth_class structure.\n\t(auth_register): Replaces auth_create.\n\t(ne_set_server_auth, ne_set_proxy_auth): Simplify, use\n\tauth_register.\n\t(everywhere): Reference req_hdr etc via ->spec-> reference.\n\nSun Jul 28 12:29:23 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (proxy_tunnel): Reset 'persisted' flag, so that a\n\tnewly tunnelled connection is not treated as persistent.\n\nSun Jul 28 12:26:49 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_string.h (CONCAT2, CONCAT3, CONCAT4): Removed macros.\n\nThu Jul 25 23:16:00 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (send_request): Don't clear retry until a\n\tstatus-line has been read.\n\nThu Jul 25 00:03:17 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_auth.c (basic_challenge, request_basic): Use ne_concat not\n\tthe CONCAT? macros.\n\n\t* ne_basic.c (ne_mkcol): Use ne_concat not the CONCAT2 macro.\n\nWed Jul 24 00:16:39 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_string.c (count_concat, do_concat): Factored out from\n\tne_buffer_concat.\n\t(ne_buffer_concat): Rewrite to use count_concat, do_concat.\n\t(ne_concat): New (resurrected) function.\n\nThu Jul 18 21:52:12 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (proxy_tunnel): Don't use server.hostport in\n\tRequest-URI; always include `:port' even if default port is used;\n\tfix CONNECT through Inktomi Traffic-Server.\n\nThu Jul 18 21:33:43 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (aborted, ne_set_request_body_fd): Use ne_strerror.\n\n\t* ne_session.c (ne_ssl_load_pem, ne_ssl_load_pkcs12): Use ne_strerror.\n\n\t* ne_basic.c (get_to_fd): Use ne_strerror.\n\nThu Jul 18 20:19:30 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_string.c (ne_strerror): New function.\n\n\t* ne_socket.c (set_strerror): Move portability logic to\n\tne_strerror; just use that here.\n\nThu Jul 18 20:00:46 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c (read_raw, write_raw): Don't re-evaluate 'errno',\n\tper Ulrich Drepper's advice.\n\nWed Jul 17 23:47:01 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c (struct ne_socket_s): Store buffer for error string.\n\t(set_error, set_strerror): New macros.\n\t(everywhere): Use set_error, set_strerror or ne_snprintf to set\n\tthe socket error string.\n\nWed Jul 17 23:19:18 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_utils.c (ne_version_match): Fix inverted minor version test.\n\nSun Jul 14 20:13:59 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_uri.h (ne_uri): Store port as unsigned.\n\n\t* ne_uri.c (ne_uri_defaultport): Return unsigned int, and zero for\n\tundefined port.\n\nSun Jul 14 20:07:35 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.c (ne_session_proxy): Take port parameter as unsigned\n\tint, as per ne_session_create.\n\nSun Jul 14 20:03:21 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (strip_eol): Take ssize_t 'len' parameter.\n\t(read_message_header): Use ssize_t for 'n'.\n\nSun Jul 14 12:45:40 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c (ne_sock_use_ssl_os): Unconditionally enable\n\tSSL_MODE_AUTO_RETRY now OpenSSL 0.9.6 is required.\n\nSun Jul 14 12:15:40 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_xml.h (NE_XML_MEDIA_TYPE): New definition.\n\n\t* ne_acl.c (ne_acl_set),\n\t* ne_props.c (ne_proppatch, propfind): Use NE_XML_MEDIA_TYPE,\n\trather than hard-coding the incorrect \"text/xml\" media type.\n\nSun Jul 14 10:53:33 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_utils.c (ne_version_match): Replace ne_version_minimum.\n\nSat Jul 13 11:40:37 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.c (ne_negotiate_ssl): Include socket error string in\n\tsession error if SSL negotiation fails.\n\nSat Jul 13 11:27:50 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c (error_ossl): New function.\n\t(ERROR_SSL_STRING): Removed macro.\n\t(CAST2INT): New macro; safety harness for OpenSSL compatibility.\n\t(read_ossl, write_ossl): Use error_ossl, CAST2INT.\n\t(ne_sock_use_ssl_os): Use error_ssl.\n\nSat Jul 13 11:16:07 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c: Define ECONNRESET as WSAECONNRESET on Win32.\n\nSat Jul 13 10:10:03 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_private.h (struct ne_session_s): Replace 'reqcount' with\n\t'persisted' flag.\n\n\t* ne_request.c (ne_end_request): Set 'persisted' flag if\n\tconnection is left open.\n\t(send_request): Adjust to allow retry if 'persisted' flag is set.\n\t(init_socket): Clear 'persisted' flag here...\n\t(open_connection): ... rather than here.\n\nWed Jul 10 22:51:39 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (RETRY_RET): Retry on an NE_SOCK_RESET too.\n\t(send_request): Fix to only retry if not on the first request on a\n\tconnection (close_not_retried test).\n\nSun Jul  7 20:49:09 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.h: Add NE_SOCK_RESET return value; improve comments.\n\n\t* ne_socket.c (read_raw, write_raw): Return NE_SOCK_RESET if an\n\tECONNRESET error is received when reading or writing.\n\nSat Jul  6 13:30:15 2002  Joe Orton  <joe@manyfish.co.uk>\n\t\n\t* ne_request.c (read_status_line, discard_headers): New functions,\n\tsplit out from send_request.\n\t(send_request_body): Move debugging here from send_request.\n\t(RETRY_RET): Renamed from CAN_RETRY.\n\t(send_request): Simplify: remove complex 100-continue graceful\n\tfailure logic; use read_status_line, discard_headers, RETRY_RET.\n\tFix to only send request body once (expect_100_once test case).\n\tFix to not return NE_RETRY if reading status-line other than the\n\tfirst fails (fail_eof_continued test case).\n\nFri Jul  5 21:47:49 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (build_request): Fix from previous commit: clear\n\tthe buffer before building the request.\n\nFri Jul  5 21:00:20 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (build_request): Fold Host header and Request-Line\n\tinto single ne_buffer_concat call.  Don't set req->use_expect100\n\there.  Fold an if/else into an ?:.  Optimise to use\n\tne_buffer_append to add 100-continue, user-supplied headers, and\n\ttrailing EOL, since they all have known lengths.\n\t(send_request): Take request data as argument.\n\t(ne_begin_request): Call build_request here; pass to send_request.\n\tMove Expect100 logic here.\n\nFri Jul  5 17:12:56 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_basic.c (ne_read_file): Removed function.\n\nFri Jul  5 17:10:11 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_compress.c (process_footer): Take unsigned char buffer.\n\tStore calculated CRC in a uLong.\n\t(do_inflate, gz_reader): Cast buffers to unsigned char for\n\tstrict compatibility with zlib interface.\n\nWed Jul  3 19:21:17 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (struct ne_request_s): Use a fixed char array for\n\trespbuf field.\n\t(ne_request_create, ne_request_destroy): Don't allocate respbuf\n\tdynamically.\n\t(send_request): Move 'buffer' to appropriate scope.\n\t(ne_request_dispatch): Remove 'buffer'; read into respbuf.\n\nTue Jul  2 08:35:05 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (proxy_tunnel): Remove redundant sess->connected\n\tassignment.\n\nSun Jun 30 21:04:50 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (ne_begin_request): Only set host->resolved if\n\tlookup is successful.\n\nSun Jun 30 18:25:51 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (SOCK_ERR): New macro.\n\t(struct ne_request_s): Remove 'forced_close' field.\n\t(aborted): Renamed from set_sockerr; also closes connection and\n\tprints message in debug log.\n\t(send_request_body): Don't use set_sockerr or set forced_close.\n\t(read_response_block, read_message_header): Use SOCK_ERR; adjust\n\tto use aborted().\n\t(ne_read_response_block, read_response_headers): Don't set\n\tforced_close.\n\t(CAN_RETRY): New macro.\n\t(send_request): Adjust to use CAN_RETRY(); use aborted() to make\n\tsure connection is closed in error cases.\n\t(ne_begin_request): Don't close connection here in error cases;\n\tdon't use forced_close.\n\t(open_connection): Adjust to use aborted() not set_sockerr().\n\nSun Jun 30 17:26:41 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.c (ne_close_connection): Clarify debug messages.\n\nSun Jun 30 14:36:11 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (read_response_block): Fail on chunk size lines\n\twhich contain no valid chunk size digits.\n\nSun Jun 30 12:35:35 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.c (ne_negotiate_ssl): Use ne_get_session rather\n\tthan req->session.\n\n\t* ne_request.c (struct header_handler, struct body_reader,\n\tstruct ne_request_s): Moved from ne_private.h.\n\nSun Jun 30 12:13:58 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\tCleanup of response handling:\n\t\n\t* ne_private.h (struct ne_response): Replace 'is_chunked' field with\n\t'mode' enum.\n\n\t* ne_request.c (te_hdr_handler): Set mode.\n\t(connection_hdr_handler): Reset can_persist for 'close'.\n\t(clength_hdr_handler): New function.\n\t(ne_request_create): Use clength_hdr_handler to parse Content-Length\n\theader.\n\t(read_response_block, ne_read_response_block): Adapt for 'mode' enum; \n\tsimplify.\n\t(normalize_response_length): Removed function.\n\t(ne_begin_request): Fold in normalize_response_length logic.\n\t(ne_end_request): Simplify logic.\n\nSun Jun 30 11:08:26 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.c: Remove X509_NAME workaround in favour of a\n\tneon.mak change.\n\nTue Jun 25 23:14:34 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.c: Undefine X509_NAME if it is defined (by a Windows\n\theader).\n\nTue Jun 25 22:51:15 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c: Rename READ_BUFFER to RDBUFSIZ.\n\nTue Jun 25 21:07:13 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_private.h (struct host_info): Store port as unsigned int.\n\n\t* ne_session.c (set_hostport, set_hostinfo, ne_session_create):\n\tTake port argument as unsigned int.\n\n\t* ne_socket.c (ne_sock_connect): Take port argument as unsigned\n\tint.\n\nTue Jun 25 20:59:14 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_utils.h [__GNUCC__] (NE_DEBUG): Remove implementation using\n\tGNU C extensions.\n\nSun Jun 23 22:47:52 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (set_request_uri): Renamed from ne_set_request_uri;\n\tmade static.\n\t(ne_request_create): Update accordingly.\n\n\t* ne_private.h (ne_set_request_uri): Removed prototype.\n\t\nSun Jun 23 15:40:57 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (send_request, ne_request_destroy): Free\n\treason_phrase now it is malloc-allocated.\n\nSun Jun 23 14:59:04 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\tSimplify given loss of const qualifier on ne_status.reason_phrase:\n\n\t* ne_props.c (struct propstat): Remove r_phrase field.\n\t(end_propstat, free_propset): Use status.reason_phrase not\n\tr_phrase field.\n\nSun Jun 23 14:42:22 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_207.h (ne_207_end_response, ne_207_end_propstat): Remove\n\tstatus_line parameter from callbacks.\n\n\t* ne_207.c (struct ne_207_parser_s): Remove status_line field.\n\t(end_element): Don't store status_line.\n\t(handle_error): Drop status_line argument, recreate dummy status\n\tline from status object.\n\t(end_response, end_propstat): Drop status_line arguments.\n\n\t* ne_props.c (end_propstat, end_response): Drop status_line\n\targuments.\n\nSun Jun 23 14:39:00 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_utils.h (ne_status): Remove const qualifier from\n\t'reason_phrase' field.\n\t\n\t* ne_utils.c (ne_parse_statusline): strdup the reason_phrase on\n\tsuccessful return.\n\nSun Jun 23 11:39:24 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_compress.c (struct ne_decompress_s): Replace footer union\n\twith buffer.\n\t(BUF2UINT): New macro.\n\t(process_footer): Convert footer to integer in a portable manner,\n\tusing BUF2UINT.\n\nSun Jun 23 09:05:25 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_compress.c (ne_decompress_s): Use unsigned int for 32-bit\n\tintegers, not uLong (fix for 64-bit platforms).\n\nWed Jun 19 18:46:40 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.c (ne_session_destroy): Don't leak the proxy\n\thostname.\n\nSun Jun 16 14:09:31 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (read_response_block): Use NE_FMT_SSIZE_T rather\n\tthan %d, cast field precision argument to int.\n\t(ne_pull_request_body): Use ssize_t for store callback return\n\tvalue, use NE_FMT_SSIZE_T rather than %d, cast field precision\n\targument to int.\n\nSun Jun 16 12:15:19 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.c (ne_negotiate_ssl): Don't leak peer certificate in\n\terror cases.  Fix spelling mistake in error message.\n\nSun Jun 16 11:23:23 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (open_connection): When SSL negotation fails after\n\tdoing CONNECT request, use ne_close_connection so that\n\tsess->connection is reset to 0, and ne_sock_close isn't called\n\ttwice for the socket.\n\nWed Jun 12 23:22:20 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_props.c (ne_proppatch): Add missing call to\n\tne_lock_using_resource.\n\nMon Jun 10 20:45:27 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_auth.c (verify_response): Remove redundant prototype, fix\n\tsscanf format string to use signed integer.\n\nMon Jun 10 20:13:57 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_compress.c (do_inflate): Continue calling inflate() whilst\n\tunconsumed input remains: fix from Justin Erenkrantz\n\t<jerenkrantz@apache.org>.\n\nMon Jun 10 19:53:59 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c (ne_sock_readline): If a complete line is found in\n\tthe buffer, avoid the memmove() and simply copy the line directly\n\tout of the buffer.\n\nSun Jun  9 11:39:20 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_redirect.c (post_send): Perform simple relative URI\n\tresolution.\n\nTue Jun  4 16:51:54 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_uri.c (ne_path_parent): Simplify.\n\nMon Jun  3 17:50:27 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_cookies.c (set_cookie_hdl): Avoid free'ing cookie name/value,\n\tthanks to Dan Mullen.\n\nMon Jun  3 17:45:33 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_string.c (ne_base64): Use size_t for outlen.\n\nMon Jun  3 17:42:34 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_utils.h, ne_socket.h [WIN32]: Move ssize_t definition to\n\tne_socket.h.\n\nMon Jun  3 17:27:21 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (read_response_block): Use correct types for\n\tpassing to/from ne_sock_*.\n\nMon Jun  3 11:32:20 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_compress.c (ne_decompress_destroy): Don't fail if response\n\treader callback is never invoked.\n\nSun Jun  2 12:51:35 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c (read_ossl, read_raw): Call readable_{ossl,raw}\n\tfunction here.\n\t(ne_sock_read, ne_sock_peek, ne_sock_readline): Remove explicit\n\tcalls to ops->readable before ops->read.\n\nThu May 30 22:00:07 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c (ne_sock_readline): Optimise to use socket read\n\tbuffer directly, and use ->read (and ->readable) functions.\n\nTue May 28 17:00:34 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.c (ne_session_destroy): Don't free proxy.hostport,\n\tsince it's no longer set.\n\nSun May 26 19:11:46 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_xml.c: #error if no expat header is configured; flatten\n\tnested #if's, include libxml/xmlversion.h if present.\n\nSun May 26 19:09:04 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_utils.c: Include libxml/xmlversion.h if present.\n\nSun May 26 11:55:30 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.c (set_hostport): Renamed from get_hostport: set\n\thost_info field directly; take defaultport argument.\n\t(set_hostinfo): Don't use get_hostport.\n\t(ne_session_create): Use set_hostinfo and set_hostport; pass\n\tin default port correctly for http:/https:.\n\nThu May 23 19:44:44 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_xml.c (resolve_nspace): Split out from parse_element.\n\t(ne_xml_get_attr): Take parser object, and optional\n\tnamespace; resolve the namespace if necessary.\n\t(parse_element): Use resolve_nspace.\n\n\t* ne_props.c (startelm): Use new ne_xml_get_attr interface.\n\nWed May 22 22:29:05 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_dates.c: Renamed HAVE_TM_GMTOFF to HAVE_STRUCT_TM_TM_GMTOFF\n\tfrom use of AC_CHECK_MEMBERS.\n\nTue May 21 21:21:31 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_redirect.c (ne_redirect_register): Drop confirm, notify,\n\tuserdata arguments.\n\t(struct redirect): Drop most fields; add a uri structure.\n\t(auto_redirect): Removed function.\n\t(post_send): Remove functionality which retries a request with a\n\tdifferent URI to automatically follow redirects.  Qualify the URI\n\tif non-absolute.\n\t(create): Remove now redundant code.\n\t(ne_redirect_location): Return an ne_uri object.\n\nSun May 19 18:53:22 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.c (ne_set_useragent): Use strcat/malloc/strcpy\n\tdirectly, rather than CONCAT2; allow compiler optimisations.\n\t(AGENT): Renamed from NEON_USERAGENT, append space.\n\nSun May 19 17:31:43 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\tMove everything exported by ne_socket.h into ne_*/NE_* namespace;\n\tpurge inappropriate and unused interfaces.  Renaming done by Olof\n\tOberg.\n\t\n\t* ne_socket.h:\n\n\t(SOCK_FULL): Removed constant.\n\t(sock_call_progress, sock_transfer, sock_sendline,\n\tsock_send_string, sock_readfile_blocked): Removed functions.\n\t\n\t(NE_SOCK_ERROR, NE_SOCK_TIMEOUT, NE_SOCK_CLOSED):\n\tRenamed constants.\n\n\t(ne_progress, ne_block_reader): Renamed types.\n\n\t(ne_register_progress, ne_sock_init, ne_sock_exit, ne_sock_read,\n\tne_sock_peek, ne_sock_block, ne_sock_fullwrite, ne_sock_readline,\n\tne_sock_connect, ne_sock_accept, ne_sock_fd, ne_sock_error,\n\tne_sock_read_timeout, ne_name_lookup, ne_service_lookup,\n\tne_sock_use_ssl, ne_sock_use_ssl_os): Renamed functions.\n\t\n\t* ne_private.h, ne_request.c, ne_session.c: Update accordingly.\n\n\t* ne_request.c (build_request): Return the ne_buffer pointer.\n\t(send_request): Remove redundant strlen(), use known buffer\n\tlength.\n\n\t* ne_request.h: Drop ne_block_reader definition.\n\nSun May 19 13:32:12 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (ne_get_session, ne_get_request): Take const\n\trequest pointer.\n\nSun May 19 13:21:17 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_string.c (ne_buffer_ncreate): Renamed from\n\tne_buffer_create_sized.\n\n\t* ne_session.c (check_certificate, provide_client_cert): Update\n\taccordingly.\n\n\t* ne_request.c (ne_request_create): Update accordingly.\n\t\nSun May 19 13:12:14 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_string.c (ne_token): Drop quotes parameter.\n\t(ne_qtoken): Split out from ne_token.\n\n\t* ne_basic.c (dav_hdr_handler, ne_content_type_handler): Use\n\tne_qtoken.\n\n\t* ne_compress.c (find_token): Removed function.\n\t(gz_reader): Compare header value directly against \"gzip\",\n\tremove a stale comment.\n\nSun May 19 09:45:28 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.h (sock_fullread): Return ssize_t; takes buflen as\n\tsize_t.\n\t(sock_read, sock_peek): Fix prototypes to match actual definition.\n\n\t* ne_socket.c (write_raw): Return ssize_t.\n\nSat May 18 14:53:45 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_string.h (ne_buffer): Remove separate struct ne_buffer_s\n\tdefinition.\n\n\t* ne_string.c (ne_buffer_create_sized): Don't use struct\n\tne_buffer_s.\n\nSun May 12 11:33:02 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_string.c (ne_base64): Moved from base64.c.\n\n\t* base64.c, base64.h: Removed files.\n\n\t* Makefile.in: Updated accordingly.\n\n\t* ne_auth.c: Don't include base64.h.\n\nSun May 12 11:26:05 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_string.h (ne_utf8_decode, ne_utf8_encode): Removed functions.\n\nSat May 11 15:42:24 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\tAs part of patch from Olof Oberg <mill@pedgr571.sn.umu.se>:\n\t\n\t* ne_request.h (ne_destroy_fn): Renamed from typo'ed\n\tne_destory_fn.\n\n\t* ne_request.c (ne_request_destroy, ne_hook_destroy_request,\n\tne_hook_destroy_session): Update accordingly.\n\n\t* ne_session.c (ne_session_destroy): Update accordingly.\n\nThu May  9 21:44:15 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\tMajor improvements to socket layer to incorporate socket read\n\tbuffering and rewrite sock_readline, and add an abstraction layer\n\tto simplify SSL support.  Grunt work by Jeff Johnson\n\t<jbj@redhat.com>\n\t\n\t* ne_socket.c (struct iofns): New type.\n\t(struct nsocket_s): Store 'ops' pointer to I/O functions in use\n\tfor the socket.  Add buffer, bufpos, bufavail fields for read\n\tbuffering.\n\t(sock_block, sock_read, sock_peek): Reimplement to add read\n\tbuffer, simplify to use I/O functions abstraction.\n\t(readable_raw, read_raw, write_raw, readable_ossl, read_ossl,\n\twrite_ossl): Factored out from sock_read/fullwrite, avoiding\n\tin-lined ifdefs.\n\t(sock_fullwrite): Just use ops->write.\n\t(sock_readline): Simplify greatly to exploit read-buffering, return\n\tssize_t.\n\t(sock_fullread): Simplify, removing unnecessary local variables,\n\treturn ssize_t.\n\t(create_sock, sock_enable_ssl_os): Set ops pointer.\n\nWed May  8 11:54:48 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c (sock_name_lookup): Avoid casts; use INADDR_NONE.\n\t[!INADDR_NONE]: Define to (unsigned long) -1.\n\nWed May  1 22:19:18 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_locks.h (ne_lock): Document that ->token and ->owner fields\n\tmust be malloc-allocated if non-NULL.\n\nWed May  1 22:15:41 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_locks.c (get_ltoken_hdr): New function.\n\t(ne_lock): Correctly parse Coded-URL from Lock-Token response\n\theader.\n\nWed May  1 22:03:08 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_redirect.c (post_send): Adjust for ne_uri_parse handling of\n\tunspecified port.\n\nWed May  1 22:00:50 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.c (provide_client_cert): Fail if peer certificate not\n\tknown when client cert requested.\n\nWed May  1 21:58:35 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.h (ne_ssl_provide_fn): Adjust callback typedef to\n\treturn void.\n\nWed May  1 21:52:40 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.h: Remove NE_SERVERAUTH and NE_AUTHPROXY; fix\n\tNE_PROXYAUTH description.\n\nWed May  1 21:32:54 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_uri.c (ne_uri_parse): For consistency, port field is 0 if\n\tunspecified.\n\nTue Apr 30 10:05:48 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_string.c (shave_string): Removed function.\n\nTue Apr 23 21:19:53 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_props.c (start_propstat, startelm): Use ne_realloc not\n\trealloc (thanks to Jeff Johnson).\n\nTue Apr 23 20:55:56 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_xml.c: Include parser.h or libxml/parser.h, depending on\n\twhich is found.\n\nMon Apr 15 00:37:43 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (build_request, send_request): Simplify logic.\n\nSun Apr 14 16:59:50 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_props.c: Remove unused accidental 'propstat' global.\n\t(struct propstat): Add r_phrase field.\n\t(end_propstat): Dup the reason_phrase string.\n\t(free_propset): Free the reason_phrase.  Avoid another possible\n\tfree(NULL) call.\n\nSun Apr 14 12:00:54 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_basic.c (ne_content_type_handler): For text/* media types,\n\tuse default charset of ISO-8859-1.\n\nSat Apr 13 23:11:07 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_utils.h: Include trio.h if NEON_TRIO is defined.\n\nSun Apr  7 17:38:14 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (read_response_headers): Don't zero-initialize hdr.\n\nSun Apr  7 17:15:23 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (read_response_headers): Ignore whitespace between\n\theader name and colon, simplify logic a little.\n\nSun Apr  7 14:09:07 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.c (ne_ssl_readable_dname): New function.\n\nSun Apr  7 12:32:25 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_string.c (ne_buffer_destroy): Remove redundant check for data\n\tpointer being NULL.\n\nWed Apr  3 19:44:59 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\tOptimisation/simplification of header name hashing.\n\n\t* ne_request.c (hash_and_lower): Renamed from hdr_hash; convert\n\tstring to lower-case in-place too.\n\t(lower_string): Removed function.\n\t(ne_add_response_header_handler): Use hash_and_lower rather than\n\tlower_string.\n\t(HH_ITERATE): Change parameter name to 'ch'.\n\nFri Mar 29 23:00:57 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_uri.c (ne_uri_parse): Minor optimisation.\n\nMon Mar 25 21:45:36 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\tPass a lock context around during LOCK processing; search for the\n\tcorrect <activelock> element in the response body.\n\t\n\t* ne_locks.c (ne_lock_create): Don't take a path argument.\n\t(ne_unlock): Constify lock parameter.\n\t(discover_results): Don't parse out href here...\n\t(ld_create): do it here instead; renamed from create_private.\n\t(lk_startelm): New function.\n\t(lk_endelm): Renamed from end_element_lock.\n\t(ne_lock): Require a Lock-Token response header; pass lock context\n\tto callbacks.  Copy lock back out.\n\nMon Mar 25 21:35:42 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.h (NE_SSL_FAILMASK): New constant.\n\t(NE_SSL_*): Shift right one bit.\n\nMon Mar 25 21:21:18 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.c (ne_close_connection): Return void.\n\nMon Mar 25 20:09:33 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_props.c (free_propset): Avoid free(NULL).\n\nMon Mar 11 19:59:04 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_locks.c (ne_lock_using_parent): Iterate over the lock list by\n\thand: check for infinite depth locks with cover the parent too\n\t(fixing if_covered_child test).\n\nMon Mar 11 19:25:44 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (ne_request_dispatch): Move variable to scope in\n\twhich is is used.\n\nSun Mar 10 22:04:58 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* Makefile.in (NEON_BASEOBJS): Always build ne_compress.o.\n\nSun Mar 10 22:01:54 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_compress.c [!NEON_ZLIB] (ne_decompress_reader,\n\tne_decompress_destroy): Add stubs.\n\nSun Mar 10 21:42:11 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_locks.c (struct discover_ctx): Store an ne_session pointer.\n\t(discover_results): If lock URI is not an absoluteURI, qualify it\n\tusing the server host/port/scheme from the session.  Don't leak\n\tthe lock object.\n\t(create_private): Simplify, use ne_lock_create.\n\nThu Mar  7 20:08:07 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_uri.c (ne_uri_defaultport): Fix default port number for https\n\tscheme.\n\nWed Mar  6 21:22:23 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_locks.c (lk_pre_send): Use an absoluteURI in the If: header.\n\nWed Mar  6 21:15:00 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_uri.c (ne_uri_unparse): New function.\n\nTue Mar  5 22:57:00 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_uri.c (ne_uri_cmp): Compare hostnames and schemes\n\tcase-insensitively, and compare empty abspath and \"/\" as\n\tequivalent, as per RFC 2616.\n\nTue Mar  5 20:53:54 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_uri.c (ne_uri_defaultport): New function.\n\nMon Mar  4 21:10:29 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_uri.h (ne_uri): Renamed from struct uri.\n\n\t* ne_uri.c (ne_path_parent): Renamed from uri_parent.\n\t(ne_path_has_trailing_slash): Renamed from uri_has_trailing_slash.\n\t(uri_abspath, uri_absolute): Removed.\n\t(ne_uri_parse): Renamed from uri_parse, don't take a 'defaults'\n\tparameter.\n\t(ne_uri_free): Renamed from uri_free.\n\t(ne_path_unescape): Renamed from uri_unescape.\n\t(ne_path_escape): Renamed from uri_abspath_escape.\n\t(ne_uri_cmp): Renamed from uri_cmp.\n\t(ne_path_compare): Renamed from uri_compare.\n\t(ne_path_childof): Renamed from uri_childof.\n\n\t* ne_basic.c, ne_locks.c, ne_uri.c, ne_redirect.c, ne_session.c,\n\tne_session.h: all callers changed.\n\nMon Mar  4 01:03:23 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (strip_eol): Fix potential segfault.\n\nMon Mar  4 00:38:10 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_locks.c (insert_lock): New function.\n\t(ne_lockstore_add, submit_lock): use insert_lock.\n\nMon Mar  4 00:33:39 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_locks.c (ne_lockstore_remove): Free list item.\n\nMon Mar  4 00:31:08 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_locks.c (free_list): Really destroy the lock.\n\t(ne_lock_free): Don't free the lock object itself.\n\nMon Mar  4 00:17:18 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (ne_request_destroy): Free accessor hook list.\n\nSun Mar  3 20:35:09 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\tChanges to lock interface; replacing \"lock session\" with a lock\n\tstore, which can be registered with an ne_session.  Lock objects\n\tnow store URI as complete URI structure.\n\t\n\t* ne_locks.h (struct ne_lock): Store URI as complete URI\n\tstructure.  Remove next/prev fields.\n\t(ne_lock_store): New type.\n\n\t* ne_locks.c (struct lock_list): New type.\n\t(struct ne_lock_store_s): Replaces ne_lock_session_s; store\n\tlock_list pointers for stored locks, cursor, and locks to\n\tsubmit.\n\t(ne_lock_create): New function.\n\t(lk_create): Renamed from create.\n\t(lk_pre_send): Renamed from pre_send; adjust for lock list\n\ttype and to use URI path.\n\t(free_list): New function; split out from old 'destroy'.\n\t(lk_destroy): Renamed from destroy; use free_list.\n\t(ne_lockstore_create, ne_lockstore_destroy, \n\tne_lockstore_first, ne_lockstore_next): New functions.\n\t(ne_lockstore_register): Most of old ne_lock_register.\n\t(submit_lock): Adjusted for lock_list type.\n\t(ne_lockstore_findbyuri): Renamed from ne_lock_find; use\n\tfull URI structure.\n\t(ne_lock_using_resource, ne_lock_using_parent): Adjusted\n\tfor lock_list/full URI changes.\n\t(ne_lock_iterate): Removed function.\n\t(ne_lockstore_add, ne_lockstore_remove): Renamed from\n\tne_lock_add, ne_lock_copy; adjusted for lock_list/full URI.\n\t(ne_lock_copy): Adjusted for full URI.\n\t(ne_lock_create, ne_lock_destroy): New function.\n\t(ne_lock, ne_lock_refresh, ne_unlock): Adjusted for full URI.\n\nSun Mar  3 15:23:40 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_uri.c (uri_cmp): New function.\n\nSun Mar  3 11:01:30 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.c (ne_fill_server_uri): New function.\n\nMon Feb 25 21:25:27 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_utils.c (version_string): Add zlib version.\n\nMon Feb 25 20:49:07 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* (everywhere): Replace use of snprintf, vsnprintf with\n\tne_snprintf, ne_vsnprintf so that trio replacements are used when\n\tappropriate.\n\n\t* ne_dates.h: Pick up ne_utils.h for ne_{v,}snprintf defines.\n\t\nSun Feb 24 11:23:05 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_utils.h: Define ne_snprintf, ne_vsnprintf for trio or\n\tnon-trio builds.\n\nSun Feb 24 11:20:42 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* Makefile.in (check-incl): Add target to check that each header\n\tfile can be included standalone.\n\nSun Feb 24 11:17:54 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_xml.h: Add missing sys/types.h include.\n\nSun Feb 24 11:12:22 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_utils.h: Remove HTTP_QUOTES, HTTP_WHITESPACE globals.\n\n\t* ne_cookies.c (set_cookie_hdl): Don't use HTTP_QUOTES,\n\tHTTP_WHITESPACE globals.\n\nWed Feb 20 19:32:48 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (set_sockerr, ne_set_request_body_fd,\n\tsend_request): Use ne_set_error rather than accessing session\n\terror directly.\n\nTue Feb 19 21:34:59 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_utils.c (version_string) [NEON_SOCKS]: Mention SOCKSv5\n\tsupport.\n\n\t* ne_socket.c (sock_init) [NEON_SOCKS]: Call SOCKSinit.\n\nTue Feb 19 19:21:07 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (open_connection): Remove notify_status call\n\tduplicated with ne_negotiate_ssl.\n\nTue Feb 19 19:16:44 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c (sock_get_version): Removed function.\n\nTue Feb 19 19:12:52 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.c (ne_ssl_provide_ccert): Moved outside ifdef\n\tNEON_SSL.\n\t[!NEON_SSL] (ne_ssl_load_pem, ne_ssl_load_pkcs12,\n\tne_ssl_keypw_prompt): Added stubs.\n\nSun Feb 17 21:15:34 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.c (ne_session_create, ne_session_destroy): Only use\n\tthe SSL context is SSL is being used for the session.\n\nSun Feb 17 20:19:05 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\tAdd back client certificate support, much improved.\n\n\t* ne_private.h (struct ne_session_s): Add client cert/key fields,\n\tprovider, privkey password callbacks.\n\t\n\t* ne_socket.c (sock_init): Call PKCS12_PBE_add.\n\t(sock_enable_ssl_os): Add optional 'appdata' argument.\n\t(sock_enable_ssl): Adjust accordingly.\n\n\t* ne_session.c (provide_client_cert, privkey_prompt,\n\tne_ssl_keypw_prompt, ne_ssl_load_pkcs12, ne_ssl_load_pem,\n\tne_ssl_provide_ccert): New functions.\n\t(ne_negotiate_ssl): Pass session as appdata to sock_enable_ssl_os.\n\nSun Feb 17 12:32:34 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.c (make_dname): New function.\n\t(check_certificate): Use make_dname.\n\nSun Feb 17 11:29:10 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_basic.c (struct get_context): Remove unused 'progress' field,\n\tadd 'session' field.\n\t(get_to_fd, content_range_hdr_handler, clength_hdr_handler): Set\n\tsession error directly.\n\t(clength_hdr_handler): Also fix check for expected range.\n\t(everywhere): Initialize session field, don't set session error;\n\tuse NE_FMT_OFF_T to print off_t's rather than casting to long int.\n\nSat Feb 16 23:24:10 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_xml.h (NE_XML_STRIPWS): New element flag.\n\t\n\t* ne_xml.c (start_element): Clear cdata buffer if not in mixed\n\tmode.  (char_data): Only strip leading whitespace if\n\tNE_XML_STRIPWS is set for the element.\n\nSat Feb 16 14:52:59 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_compress.c (enum state): New state NE_Z_AFTER_DATA.\n\t(struct ne_decompress_s): Add fields for storing and parsing\n\tstream footer; add checksum field for storing current crc.\n\t(process_footer): New function.\n\t(do_inflate): Compute checksum.  Switch to AFTER_DATA state and\n\tprocess footer after reading DEFLATE data.\n\t(gz_reader): Fail on trailing content.  Handle AFTER_DATA state.\n\t(ne_decompress_destroy): Return error if final state was not\n\tPASSTHROUGH, or FINISHED.\n\t(ne_decompress_reader): Initialize crc.\n\nSat Feb 16 14:26:54 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_compress.c (ne_decompress_destroy): Fix potential segfault\n\twith use-after-free.\n\nThu Feb 14 16:50:40 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (read_response_headers): Ignore header lines\n\twithout a ':', rather than failing the request.\n\nTue Feb 12 20:17:49 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (read_response_block): Read chunk size as unsigned\n\tusing strtoul; check that it fits within an unsigned int (and\n\thence, probably a size_t).\n\nTue Feb 12 20:15:13 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_string.h (STRIP_EOL): Removed macro.\n\nMon Feb 11 22:11:03 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.c (match_hostname): Match fully-qualified hostnames\n\tagainst commonName with leading \"*.\" wildcard.\n\nMon Feb 11 20:47:28 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.c (match_hostname): New function.\n\t(check_certificate): Use it.\n\nSun Feb 10 00:50:49 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (lookup_host): Set error string on lookup failure.\n\nSun Feb 10 00:34:42 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (strip_eol): New function; more efficient\n\tSTRIP_EOL.\n\t(send_request): Use strip_eol.\n\t(read_message_header): Use strip_eol, simplify, remove redundant\n\tvariables.\n\nSat Feb  9 21:02:31 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.c (ne_set_error): Drop STRIP_EOL call.\n\nSat Feb  9 21:01:01 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.c (ne_set_error): Take printf-style format string +\n\tvarargs list.\n\nSat Feb  9 16:15:09 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.h (SOCKET_READ_TIMEOUT): Moved to ne_socket.c.\n\t\n\t* ne_socket.c (struct nsocket_s): Add rdtimeout field.\n\t(create_sock): Initialize rdtimeout to SOCKET_READ_TIMEOUT.\n\t(sock_read, sock_recv): Use ->rdtimeout field for read timeout.\n\t(sock_set_read_timeout): New function.\n\n\t* ne_private.h (struct ne_session_s): Add rdtimeout field.\n\t\n\t* ne_session.c (ne_set_read_timeout): New function.\n\n\t* ne_request.c (init_socket): New function.\n\t(open_connection): Use init_socket.\n\t\nSat Feb  9 15:11:59 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.c (ne_session_destroy): Don't leak the server cert.\n\nSat Feb  9 09:59:11 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.c (check_certificate): Only call verification\n\tcallback once per certificate; watch for the server cert\n\tchanging and fail if it does.\n\nWed Feb  6 20:28:27 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.c (check_certificate): Only call verification\n\tcallback if failures is non-zero.\n\t(ne_ssl_load_ca): Renamed from ne_ssl_add_ca.\n\t(ne_ssl_load_default_ca): New function.\n\nWed Feb  6 20:21:29 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c (sock_init): Cache and return result of\n\tinitialization.\n\nWed Feb  6 01:12:20 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.c (check_certificate): Ignore cert validity errors\n\tfrom OpenSSL since these are duplicated.\n\nWed Feb  6 01:08:57 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.c (ne_negotiate_ssl): Fix for invalidating cached\n\tSSL_SESSION.\n\nWed Feb  6 01:03:37 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.c [!NEON_SSL] (STUB): New function.\n\t(ne_negotiate_ssl, ne_ssl_add_ca): Implement using STUB.\n\nTue Feb  5 19:56:43 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.h (ne_ssl_certificate): New type.\n\t\n\t* ne_session.c (ne_session_create) [NEON_SSL]: Create the SSL_CTX\n\tstructure.  \n\t(ne_ssl_get_context): Return the SSL_CTX rather than setting it.  \n\t(ne_session_destroy): Free the SSL_CTX.\n\n\t(asn1time_to_string): Function moved in from sslcerts.c.\n\t(check_certificate): Use OpenSSL's internal validity result.\n\tPass back an ne_ssl_certificate to the verification function; \n\tincluding validity dates.\n\t(ne_ssl_add_ca): New function, registers CA certs.\n\nSat Feb  2 14:05:26 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c (sock_enable_ssl_os): Take an optional SSL_SESSION\n\targument.\n\n\t* ne_private.h (struct ne_session_s): Add an SSL_SESSION field.\n\t\n\t* ne_session.c (ne_negotiate_ssl): Pass stored SSL session to\n\tsock_enable_ssl_os, cache session after successful negotiation.\n\t(ne_session_destroy): Free cached session.\n\nSat Feb  2 10:45:46 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c, ne_utils.c: Globally replace ENABLE_SSL cpp symbol\n\twith NEON_SSL.\n\nSat Feb  2 09:43:27 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.c (check_certificate): Use 1K on-stack buffer.\n\nSat Feb  2 08:27:08 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_private.h (struct host_info): Add 'resolved' flag.\n\t(struct ne_session_s): Add scheme field, rename have_proxy to\n\tuse_proxy, remove proxy_decider.\n\t(struct ne_request_s): Remove use_proxy field.\n\n\t* ne_request.c (set_sockerr, ne_set_request_uri, build_request, \n\topen_connection): Use session->use_proxy field to determine\n\twhether proxy is used.\n\t(ne_request_create): Drop use of proxy_decider callback.\n\t(lookup_host): Moved here from ne_session.c.\n\t(ne_begin_request): Lookup server/proxy hostname if not already\n\tresolved.\n\n\t* ne_session.c (ne_session_create): Moved within file; takes\n\tscheme, and server hostname, port as arguments.\n\t(ne_ssl_enable, ne_session_decide_proxy, ne_session_server):\n\tRemoved functions.\n\t(ne_get_scheme): Simply return scheme field.\n\nFri Feb  1 23:12:38 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (add_fixed_headers): Remove last traces of TLS\n\tupgrade support.\n\nThu Jan 31 20:50:12 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_private.h (struct ne_session_s): Rename use_secure to\n\tuse_ssl; removed nssl_context, added SSL_CTX, server cert, verify\n\tcallback pointers.\n\n\t* ne_request.c (send_request): Remove support for TLS upgrade.\n\t(open_connection): Use ne_negotiate_ssl; close socket properly if\n\tnegotiation fails.\n\n\t* ne_session.c (ne_session_destroy): Free SSL_CTX stored in\n\tsession.\n\t(ne_ssl_set_context, ne_ssl_set_verify, verify_err, getx509field,\n\tcheck_context, ne_negotiate_ssl, ne_ssl_server_cert): New\n\tfunctions.\n\t(ne_set_secure_context, ne_set_request_secure_upgrade,\n\tne_set_accept_secure_upgrade): Removed functions.\n\t(ne_ssl_enable): Renamed from ne_set_secure.\n\n\t* ne_socket.c (struct nssl_context_s): Removed type.\n\t(sock_create_ssl_context, sock_destroy_ssl_context,\n\tsock_disable_*, key_prompt_cb, sock_set_key_prompt,\n\tsock_set_client_cert): Removed functions.\n\t(sock_enable_ssl_os): Renamed from sock_make_secure; take an\n\tSSL_CTX pointer, and optionally pass out the SSL structure.\n\t(sock_enable_ssl): New function.\n\t\nWed Jan 30 19:47:42 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_string.c (ne_buffer_concat, ne_buffer_zappend,\n\tne_buffer_append, ne_buffer_grow): Don't return success value,\n\tpresume universe ends at OOM.\n\nSat Jan 26 10:57:42 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_compress.c: Renamed enum state constants to have prefix\n\tNE_Z_, to avoid conflict with Windows headers (Branko ibej).\n\nMon Jan 14 20:26:31 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_string.c (ne_concat): Removed function - it didn't work, and\n\tit wasn't used.\n\nMon Jan 14 02:09:38 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_basic.c (ne_content_type_handler): Parse charset parameter.\n\nSun Jan 13 14:29:00 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_basic.c (ne_content_type_handler): Remove trailing '/' from\n\tparsed type, fix search for parms separator (Greg Stein).\n\nSun Jan 13 12:07:51 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_207.c (ne_simple_request): Drop unused Content-Type handling.\n\nThu Jan 10 00:39:17 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (hdr_hash): Mark as inline.\n\nTue Jan  8 22:03:42 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_locks.c (add_timeout_header): New function.  (ne_lock,\n\tne_lock_refresh): Send a Timeout header if lock->timeout is set.\n\nMon Jan  7 21:48:38 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_locks.c (parse_timeout): Fix parsing lock timeout (Arun\n\tGarg).\n\nMon Dec 17 22:46:36 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_private.h (struct ne_session_s): Make expect100_works a plain\n\tinteger (rather than a bitfield).\n\nSun Dec  9 14:04:27 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_string.c (ne_buffer_grow, ne_buffer_create_sized): Don't\n\tzero-fill new memory.  (ne_buffer_concat): Zero terminate the\n\tstring as _grow doesn't do it.\n\nSun Dec  9 13:31:55 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_string.c (ne_buffer_zappend): Minor optimisation; implement\n\tusing ne_buffer_append.\n\nSun Dec  9 13:18:35 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_string.c (ne_buffer_concat): Optimise to use time O(n) [n ==\n\ttotal string length).\n\nSun Dec  9 11:57:56 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* Makefile.in (NEON_DAVOBJS): Remove ne_acl.o.\n\nSat Dec  8 01:11:30 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (ne_pull_request_body): Use NE_FMT_SIZE_T in\n\tdebugging message; cast size_t to int to avoid GCC warning for\n\tfield size parameter.  (set_body_size): Use NE_FMT_SIZE_T.\n\n\t* ne_xml.c (ne_xml_parse): Similarly.\n\nMon Dec  3 19:56:07 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.c (ne_session_destroy): Return void.\n\nSat Dec  1 18:37:43 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_auth.c (ah_create): Reset attempt counter\n\there... (ah_post_send): ...rather than here.\n\nTue Nov 27 21:26:01 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (send_with_progress): Actually call the callback;\n\tfix for correct sock_fullwrite return codes.\n\nTue Nov 27 20:20:40 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_private.h (VERSION_PRE11): Define macro; as\n\tne_version_pre_http11.\n\n\t* ne_session.c (ne_version_pre_http11): Use VERSION_PRE11.\n\n\t* ne_request.c (add_fixed_headers, build_request, ne_end_request):\n\tUse VERSION_PRE11.\n\nSun Nov 18 19:32:56 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_locks.c (discover_results): Check status is 2xx before\n\tinvoking callback; pass NULL lock and non-NULL status pointer in\n\tfailure cases.  (create_private): Initialize lock to some \"value\n\tunspecified\" defaults.\n\nSun Nov 18 19:25:10 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_auth.c (auth_session): Rename 'tries' field to 'attempt'.\n\t(get_credentials, ah_pre_send, ah_post_send): Increment attempt\n\tcounter only when requesting credentials; reset it to zero when no\n\tauth failure is signaled.\n\nSun Nov 18 15:49:00 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_auth.h (ne_request_auth): Pass username and password as\n\tbuffers of size NE_ABUFSIZ to callback.  Add 'attempt' argument.\n\n\t* ne_auth.c (auth_session): Store username in buffer.\n\t(get_credentials, basic_challenge, digest_challenge): Updated for\n\tcallback prototype changes.  (ah_post_send): Request credentials,\n\tand retry authentication until callback returns non-zero.\n\nMon Nov 12 20:57:56 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_basic.c (get_to_fd): Really cope with short writes (thanks to\n\trado <dzusto@yahoo.com>).\n\nSun Nov  4 15:09:03 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_props.h: Define NE_ELM_PROPS_UNUSED for picking element ids\n\tfor use with the propfind XML parser.\n\nSat Nov  3 19:06:04 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_props.c (NSPACE): New macro.  (set_body, pnamecmp, startelm,\n\tfree_propset): Handle property having NULL nspace element in\n\tpropfind code.\n\nSun Oct 28 22:04:49 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_xml.c (parse_element): Prevent false matches of found prefix\n\t\"abcde\" against stored prefix \"abcdeFGH\".  Compare\n\tcase-sensitively.\n\nFri Oct 26 20:28:03 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (send_request): Fix case where persistent\n\tconnection times out, and improve error handling.\n\nThu Oct 25 20:42:24 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_props.c (ne_proppatch): Really handle properties with a NULL\n\tnamespace correctly; use the \"D:\" prefix for elements in the\n\t\"DAV:\" namespace; allow properties to have no namespace.\n\nTue Oct 16 08:54:46 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_xml.c (parse_element): Fail the parse if a namespace prefix\n\tdefinition is given with an empty value.\n\nTue Oct 16 08:52:40 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_props.h, ne_207.h: Move ne_propname definition into\n\tne_props.h.\n\nTue Oct 16 08:49:42 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_props.c (ne_proppatch): Handle properties with a NULL nspace\n\tfield correctly.\n\nSun Oct  7 19:31:06 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_acl.c (ne_acl_set) [USE_DAV_LOCKS]: Notify use of resource to\n\tlocking code.\n\nSun Oct  7 17:45:01 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_acl.c, ne_acl.h: New files, contributed by Arun Garg\n\t<arung@pspl.co.in>.\n\n\t* Makefile.in: Add ne_acl.* to build.\n\nSun Oct  7 16:10:05 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_private (struct ne_session_s): Add 'reqcount' field.\n\n\t* ne_request.c (send_request): Refactor slightly; don't loop, but\n\treturn NE_RETRY when appropriate.  Increment reqcount.\n\t(ne_begin_request): Loop if send_request returns NE_RETRY.\n\t(open_connection): Reset reqcount field.\n\nTue Oct  2 21:11:39 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_dates.c (GMTOFF): New macro.  (ne_iso8601_parse,\n\tne_rfc1123_parse, ne_rfc1036_parse, ne_asctime_parse): Use new\n\tmacro, fix up date handling on some platforms.\n\nSat Sep 29 14:20:47 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_compress.c (gz_reader): Fix tests 4 and 7: don't try to\n\tinflate after reading header if no bytes are left in the buffer.\n\nSat Sep 29 14:04:11 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_compress.c: Fix API; return an opaque object which must\n\tbe destroyed later.\n\t\n\t(ne_decompress_reader): Renamed from ne_gzip_response_body_reader.\n\tDoesn't need the session object passed in any more.\n\t(ne_decompress_destroy): Merge of co_destroy, co_post_end.\n\nSat Sep 29 13:50:43 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (ne_get_session): New function.\n\nSat Sep 29 12:52:31 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_compress.c (parse_header): Bail if flags are set to something\n\tunexpected.\n\nSat Sep 29 11:15:30 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_compress.c, ne_compress.h: New files.\n\n\t* Makefile.in: Add deps for ne_compress.\n\nThu Sep 27 09:05:24 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_redirect.c: Adapted for new hooks interface.\n\n\t* ne_cookies.c: Adapted for new hooks interface.\n\t(ne_cookie_register): New function.\n\nThu Sep 27 09:01:03 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_auth.c, ne_locks.c: Adapted for new hooks interface.  Store\n\tpointer to per-request object in the per-session object.\n\nThu Sep 27 08:48:16 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\tRe-write hooks interface to register callbacks individually rather\n\tthan as a block.  Inspired by the Apache 2.0/APR hooks interface.\n\n\t* ne_private.h (struct hook): Store a callback, userdata, id.\n\t(struct hook_request): Removed.  (struct ne_session_s): Store\n\thooks lists for create_req, pre_send, post_send, destroy_req,\n\tdestroy_sess, accessor.  (struct ne_request_s): Store accessor\n\thooks list.\n\t\n\t* ne_request.c (ne_add_hooks): Removed.\n\t(ne_hook_create_request, ne_hook_pre_send, ne_hook_post_send,\n\tne_hook_destroy_request, ne_hook_destroy_session,\n\tne_hook_session_accessor, ne_hook_request_accessor,\n\tne_null_accessor, call_access, add_hook): New functions.\n\t(ne_request_create, ne_request_destroy, build_request,\n\tne_end_request): Adapt for new interface.\n\n\t* ne_session.c (destroy_hooks): New function.\n\t(ne_session_destroy): Use it to destroy hooks lists appropriately.\n\nTue Sep 25 07:46:32 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_xml.c: Only decode UTF-8 for parsers other than libxml 1.x.\n\nTue Sep 25 07:33:09 2001  Mo DeJong  <supermo@bayarea.net>\n\n\t* src/ne_socket.c: Include <signal.h> instead of <sys/signal.h>.\n\t(sock_init): Only use signal() to ignore SIGPIPE if both\n\tHAVE_SIGNAL and HAVE_SIGPIPE are defined.\n\nTue Sep 25 07:09:53 2001  Mo DeJong  <supermo@bayarea.net>\n\n\t* ne_socket.c (sock_init): Declare local variables before invoking\n\tany instructions since that is not valid C code.\n\nSun Sep 23 10:30:54 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_auth.c (struct auth_challenge): Make members const.\n\t(clean_session): Free the realm string.  (basic_challenge,\n\tdigest_challenge): strdup the realm string.  (request_digest):\n\topaque is no longer stored quoted.  (tokenize): New function.\n\t(verify_response, auth_challenge): Rejig to use tokenize().\n\nSat Sep 22 20:17:00 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_string.c (ne_shave): Fix possible memory corruption when\n\tresult should be the empty string.\n\nThu Sep 20 21:27:57 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (ne_pull_request_body): Add debugging dump of body\n\tblocks.\n\nThu Sep 20 21:23:43 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_private.h: Remove obsolete 'if_locks' member from struct\n\tne_request_s.\n\nTue Sep 18 23:35:30 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_basic.c (ne_get_range): Handle write errors too.\n\nTue Sep 18 22:14:49 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_xml.h (ne_xml_validate_cb): Take userdata parameter.\n\n\t* ne_xml.c (find_handler): Pass validate callback the handler's\n\tuserdata.\n\n\t* ne_207.c, ne_props.c, ne_locks.c: All users changed.\n\nTue Sep 18 21:49:14 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_locks.c (ne_lock_refresh): New function.\n\nTue Sep 18 21:17:29 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_basic.c (copy_or_move): Take a depth parameter, add depth\n\theader, for COPY requests.  (ne_copy): Take depth parameter, pass\n\tthrough.  (ne_move): Adjusted accordingly.\n\nMon Sep 17 23:29:58 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_utils.c (ne_debug_init): Set debug stream to be unbuffered if\n\tsetvbuf() is available.\n\nMon Aug 27 00:36:37 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_207.c (start_element, end_element): Remember when context is\n\tvalid for a <propstat>, and only invoke callback then.\n\nSun Aug 26 22:30:39 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_basic.c (ne_get_range): Better error handling.  Cope with\n\tApache's 416 problem.\n\nSun Aug 26 18:58:47 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_auth.c: Store unquoted challenge parameters in session\n\tobject, prevent having to unquote/free them >1 times.\n\nSun Aug 26 18:57:51 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c (sock_init): Do nothing on any calls after first.\n\nSun Aug 26 12:45:04 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_basic.c (server_hdr_handler): Remove function. (ne_options):\n\tDon't add server_hdr_handler.\n\nTue Jul 17 11:25:06 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c (sock_init): Set signal dispostion for SIGPIPE to\n\tignore.\n\nSat Jun 30 12:11:44 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_utils.c (ne_supports_ssl): New function.\n\nTue Jun 19 21:57:49 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_dates.c (ne_iso8601_parse): Fix month off-by-one bug, use\n\tseparate vars for offsets.  (ne_rfc1036_parse): Fix Y2K bug,\n\tparsing problem.\n\nTue Jun 19 21:57:42 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_dates.c (ne_iso8601_parse): New function.\n\nSun Jun 10 15:39:40 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (send_with_progress): New function.\n\t(send_request_body): Use send_with_progress to trigger progress\n\tcallbacks if necessary.\n\nSat Jun  9 15:42:33 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_string.h: Bring back NE_ASC2HEX/HEX2ASC.\n\n\t* ne_md5.c: Use them.\n\nSat Jun  9 15:42:08 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_xml.h: Include ne_defs.h.\n\nFri Jun  8 23:02:49 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.h, ne_socket.c: Update for includes (Mo DeJong).\n\nFri Jun  8 21:34:00 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_basic.c (dav_hdr_handler): Use ne_token.\n\nSat Jun  2 14:37:07 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_private.h: Renamed from http_private.h.\n\nSat Jun  2 14:35:23 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_auth.c, ne_auth.h: Renamed from http_auth.c, ne_auth.h.\n\nSat Jun  2 14:35:02 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_cookies.c, ne_cookies.h: Renamed from http_cookies.c,\n\thttp_cookies.h.\n\nSat Jun  2 14:34:51 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_dates.c, ne_dates.h: Renamed from dates.c, dates.h\n\nSat Jun  2 14:22:49 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_redirect.c, ne_redirect.h: Renamed from http_redirect.c,\n\thttp_redirec.h. Big rename... s/http_/ne_g/\n\nSat Jun  2 12:54:51 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_md5.c (md5_process_block): Fix for word alignment issue on\n\tSparc from Kai Sommerfeld.\n\nWed May 30 23:15:31 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_basic.c (ne_put, ne_get, ne_put_if_unmodified, ne_get_range,\n\tne_post): Take an integer fd rather than FILE * stream.\n\t(get_to_fd): Write to fd rather than stream.\n\nWed May 30 23:08:55 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_i18n.h, ne_i18n.c: Renamed from neon_i18n.h, neon_i18n.c.\n\n\t* *.c: All changed accordingly.\n\t\nWed May 30 23:02:47 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_defs.h: Renamed from neon_defs.h.\n\n\t* *.h: All changed accordingly.\n\nWed May 30 22:58:57 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_md5.c, ne_md5.h: Renamed from md5.c, neon_md5.h\n\nWed May 30 22:55:19 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_utils.h: In-line ne_debug for GCC which can cope with varargs\n\tpreprocessor macros.  \n\nWed May 30 00:43:05 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_auth.c (ah_use_body): Removed function.  (digest_body): New\n\tfunction.  (request_digest): Use ne_pull_request_body to find the\n\tMD5 digest of the request body, when necessary.\n\nWed May 30 00:30:52 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_redirect.c: Store Request-URI, session pointer, and method\n\tstring in redirect object.  Avoid looking inside\n\tne_request/ne_session internals.\n\nWed May 30 00:04:30 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c: Re-implement request body handling in terms of a\n\tcallback which provides the request body blocks on demand.  Remove\n\t'use_body' hook, in favour of the hooks calling\n\tne_pull_request_body when necessary.  (ne_pull_request_body,\n\tbody_fd_send, body_string_send): New functions.\n\t(send_request_body): Re-implemented using ne_pull_request_body.\n\t(run_set_body_hooks): Removed function.  (ne_set_request_body_fd):\n\tReplacement for ne_set_request_body_stream, using a raw fd rather\n\tthan a FILE *.\n\nTue May 29 22:39:39 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* dav_basic.h, dav_basic.h: Removed.\n\nTue May 29 22:38:54 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_207.c (ne_simple_request, etc): Copied in from dav_basic.c.\n\nTue May 29 22:12:23 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_locks.c, ne_locks.h, ne_props.c, ne_props.h, ne_207.c,\n\tne_207.h: Big rename. dav_* -> ne_*, and so on.\n\nTue May 29 22:06:24 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_basic.c (ne_add_depth_header): Moved from dav_basic.c.\n\nTue May 29 21:55:30 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_props.c, ne_props.h: Renamed from dav_props.c, dav_props.h.\n\nTue May 29 21:43:15 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_207.c, ne_207.h: Renamed from dav_207.c, dav_207.h.\n\nTue May 29 21:22:25 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_locks.c, ne_locks.h: Renamed from dav_locks.c, dav_locks.h.\n\nTue May 29 21:21:44 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c (sock_fullwrite): Cast return value of SSL_write to\n\tsize_t to prevent comparison of signed with unsigned.\n\nTue May 29 21:05:27 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_basic.c [!NEON_NODAV]: Move ne_copy, ne_mkcol, ne_move,\n\tne_delete in here.\n\nTue May 29 20:12:50 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_uri.c, ne_uri.h: Renamed from uri.c, uri.h.\n\nTue May 29 19:17:09 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_socket.c, ne_socket.h: Renamed from socket.c, nsocket.h.\n\nTue May 29 18:58:51 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_basic.c (ne_mkcol, ne_copy, ne_move, ne_delete): Renamed from\n\tdav_*.\n\nTue May 29 17:58:09 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_basic.c (copy_or_move, dav_copy, dav_move, dav_delete,\n\tdav_mkcol): Copied in from dav_basic.c.\n\nTue May 29 17:55:33 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_basic.c, ne_basic.h: Renamed from http_basic.c, http_basic.h.\n\nTue May 29 17:47:50 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_auth.c (ah_create, ah_pre_send): Add the response body\n\thandler in pre_send, and only if qop=auth-int.\n\nWed May 16 20:54:51 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (ne_get_request_headers): Removed function.\n\nSat May 12 18:48:46 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c (read_message_header, read_response_headers): Use a\n\tfixed-size char * buffer argument rather than an ne_buffer.\n\tAppend directly to it when header-folding.\n\nMon May  7 10:42:38 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_string.c (ne_token): Use an optimized search (strchr) if\n\tquotes is NULL.\n\nMon May  7 01:33:48 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_auth.c (basic_challenge, get_cnonce): Updated for ne_base64\n\tchange.\n\nMon May  7 01:32:22 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* base64.c (ne_base64): Take length parameter.  [BASE64_TEST]\n\t(main): Remove function, obsoleted by test code.\n\nWed May  2 12:06:59 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_string.c, ne_string.h (ne_token, ne_shave): New functions,\n\tdestined to replace split_string, shave_string, etc.\n\n\t* ne_string.c [SPLIT_STRING_TEST, PAIR_STRING_TEST] (main): Remove\n\ttests, functions are obsolete.\n\nTue May  1 22:14:14 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* dates.c (ne_httpdate_parse): Moved from ne_utils.c.\n\nTue May  1 21:55:45 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_utils.c, ne_utils.h: Renamed from http_utils.c, http_utils.h.\n\tBig rename.  http_* -> ne_*. neon_* -> ne_*. DEBUG() ->\n\tNE_DEBUG().  DEBUG_* -> NE_DBG_*.\n\nTue May  1 21:35:10 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_request.c: Updated for ne_buffer changes.\n\nTue May  1 21:28:58 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_string.h (ne_buffer_size): Implement as macro.\n\n\t* ne_string.c (ne_buffer_size): Remove function.\n\nTue May  1 21:23:47 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_string.c, ne_string.h: Make ne_buffer a transparent type, and\n\tno longer be an implicit pointer type.  (ne_buffer_*): All\n\tchanged.  (ne_buffer_data, NE_BUFFER_CAST): Removed.\n\nTue May  1 21:17:40 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_string.c, ne_string.h: Renamed sbuffer -> ne_buffer.\n\tImplicit pointer removed ne_buffer type.\n\nTue May  1 21:12:15 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_string.c, ne_string.h: Renamed from string_utils.c,\n\tstring_utils.h (CVS copy'n'delete).\n\nTue May  1 20:49:46 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* md5.c (ASC2HEX, HEX2ASC): Moved here from string_utils.h.\n\n\t* string_utils.h: As above.\n\nTue May  1 20:47:20 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_request.c, http_request.h: Removed files.\n\n\t* ne_request.c, ne_request.h: Copied from old http_request.[ch].\n\tRenamed http_* -> ne_*.\n\nTue May  1 20:43:11 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* hip_xml.c renamed to ne_xml.c, hip_xml.h renamed to ne_xml.h:\n\tCVS repository copy'n'delete.\n\nTue May  1 20:41:03 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* hip_xml.c, hip_xml.h: Big rename. hip_xml_* -> ne_xml_*.\n\nTue May  1 20:37:13 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_basic.c, http_basic.h: Big rename. http_* -> ne_*.\n\nTue May  1 19:59:01 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.c: Renamed http_* to ne_*.\n\nTue May  1 19:55:47 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_alloc.h (NE_FREE): Renamed from HTTP_FREE() in http_utils.h\n\nTue May  1 19:54:42 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* socket.c (sock_make_secure): Set SSL_MODE_AUTO_RETRY when\n\tavailable.\n\nMon Apr 30 00:36:34 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_session.[ch]: New files, split down from http_request.[ch].\n\nSun Apr 29 15:02:23 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* uri.c [URITEST] (main): Remove, obsoleted by new test suite.\n\nSun Apr 29 15:01:30 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* uri.c (uri_has_trailing_slash): Return false if uri is \"\".\n\nSun Apr 29 13:53:41 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* dates.c (ne_asctime_parse, ne_rfc1123_date, ne_rfc1036_parse):\n\tSet tm_isdst to -1 in struct tm.\n\nSun Apr 29 13:28:26 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_utils.c (http_parse_statusline): Skip leading whitespace.\n\t(Johan Lindh).  (http_parse_statusline): Ensure status-code is not\n\tmore than three digits.\n\nSun Apr 29 13:26:47 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_request.c (build_request): Don't add \"Content-Length: 0\"\n\theader if no body: Squid 2.3-STABLE1 doesn't like this.\n\nSun Apr 29 13:25:16 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_auth.c (everywhere): Renamed md5_* -> ne_md5_*.\n\nSun Apr 29 13:24:12 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* md5.c: Renamed md5_* -> ne_md5_*.  (ne_ascii_to_md5,\n\tne_md5_to_ascii): Moved from string_utils.c.\n\nThu Apr 26 22:39:05 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* uri.c (uri_parse): A zero-length URI is invalid.\n\nWed Apr 25 23:11:51 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* dav_props.c (startelm): Check for xml:lang attribute and store\n\tas prop->lang.  (dav_propset_lang): New function.  (free_propset):\n\tFree lang.\n\nWed Apr 25 23:08:52 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* hip_xml.c (hip_xml_get_attr): New function.\n\nSun Apr 22 21:48:06 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* uri.c (uri_parse): Skip a userinfo@ segment if present (Johan\n\tLindh <johan@link-Data.com>).\n\nWed Apr 18 13:29:46 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* dav_locks.c (dav_lock_copy): Allow owner to be NULL.\n\nTue Apr 17 22:57:50 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_alloc.h, dav_locks.h: Add C++ inclusion safety.\n\nTue Apr 17 22:56:50 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* uri.c (uri_parse): Correctly handle URIs with no scheme or\n\thostport segments (i.e. just a path).\n\nTue Apr 10 00:29:25 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* socket.c [HAVE_SOCKS_H]: Include socks.h for SOCKSv5 support.\n\nWed Apr  4 21:41:47 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_utils.h [WIN32]: Define ssize_t (Kai).\n\nTue Apr  3 21:03:28 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* dav_locks.c (dav_lock_discover): Cope with below API change.\n\nTue Apr  3 20:43:50 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* dav_props.c (propfind): Register the flat element handler here,\n\tto pick up *any* properties and store them as 'flat' if they are\n\tnot handled by a handler further down the stack.  (make_elms,\n\tfree_elms, dav_propfind_set_flat, dav_propfind_set_complex):\n\tRemoved functions.  (dav_propfind_named): Take the list of\n\tproperty names, and call set_body here.\n\t(dav_propfind_set_private): New function.\n\nTue Apr  3 09:33:09 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_auth.h: Added C++ inclusion safety. (Kai Sommerfeld)\n\nMon Apr  2 02:39:18 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* hip_xml.c (sax_error): Add parse error callback for libxml.\n\nMon Apr  2 02:23:06 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_redirect.c (post_send): Clean up and fix logic.  Only check\n\tfor confirmation for same-server redirects.\n\nMon Apr  2 02:13:48 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_redirect.c (http_redirect_location): New function.\n\t(destroy): Removed function.  (create): Free location.\n\t(post_send): Only call notify callback for followed redirects.\n\nMon Apr  2 01:55:27 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_request.c (http_set_request_uri): Allow using the '*' URI\n\teven when using a proxy server.\n\nMon Apr  2 01:32:06 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_redirect.c (post_send): Give up on trying to follow a\n\tredirect to another server.  Return HTTP_REDIRECT on such a\n\tredirect.\n\n\t* http_redirect.c (post_send): Fix leaks of URI object (Kai\n\tSommerfeld).\n\nMon Apr  2 01:08:33 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_request.c (read_response_headers): Don't read more than 100\n\tresponse headers.\n\nMon Apr  2 00:54:43 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_request.c (http_request_dispatch): Remove mapping of auth\n\tstatus codes to return values, the hook does it now.\n\nMon Apr  2 00:53:20 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_request.c (http_set_request_uri): New function, split out\n\tfrom http_request_create. (http_request_create): Use it.\n\nMon Apr  2 00:51:23 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_auth.c (http_set_proxy_auth, http_set_server_auth): Add\n\tfailure codes.  (ah_post_send): Return failure code if\n\tauthentication fails.\n\nMon Apr  2 00:19:17 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_utils.c: Pick up xmlversion.h from libxml2.\n\t(neon_version_string): Include libxml2 version string if defined.\n\nSun Apr  1 21:40:00 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_basic.c (http_get_range): Fix total length\n\tcalculation. (Johan Lindh <johan@linkdata.se>).\n\t(clength_hdr_handler): Use range->total.\n\nSun Apr  1 21:26:09 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* hip_xml.c: Add expat2 support (Sam TH <sam@uchicago.edu>).\n\nSun Apr  1 21:07:19 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* string_utils.h (CONCAT2, CONCAT3, CONCAT4): Use ne_malloc.\n\nSun Apr  1 20:59:09 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* dav_props.c (propfind, dav_proppatch): As below.\n\nSun Apr  1 20:32:29 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_basic.c (http_post): Changed as per\n\thttp_set_request_body_buffer change.\n\n\t* dav_locks.c (dav_lock): Likewise.\n\nSun Apr  1 20:31:06 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_request.c (http_set_request_body_buffer): Pass in size\n\tparameter too.  (send_request_body): Use sized rather than\n\tNUL-terminated buffer.\n\nSun Apr  1 20:12:51 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_private.h: Added 'body_callback' request body type, and\n\tbody_cb, body_ud fields to http_req.\n\n\t* http_request.c (http_set_request_body_provider): New function.\n\t(set_body_size): New function, factored out from old\n\thttp_set_request_body_*.  (http_set_request_body_stream,\n\thttp_set_request_body_buffer): Use it.\n\nSun Apr  1 19:56:17 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* dav_props.c: Replaced 'uri' and 'depth' fields in propfind\n\thandler object with an 'http_req' pointer.  (dav_propfind_create):\n\tCreate the request object here, and set the depth header.\n\t(propfind): Changed accordingly.  (dav_propfind_destroy): Destroy\n\trequest object too.\n\n\t* dav_props.c (dav_propfind_get_request): New function.\n\t\nFri Mar 30 16:50:51 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* hip_xml.c (start_element): Quote attributes in collect (Kai\n\tSommerfeld).\n\nFri Mar 30 16:36:08 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_basic.c (http_put_if_unmodified): Changed as below.\n\nThu Mar 22 14:05:52 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_utils.c (http_dateparse): Changed as below.\n\n\t* http_auth.c (get_conce, basic_challenge): Likewise.\n\nThu Mar 22 14:04:54 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* dates.c (ne_rfc1123_date, ne_rfc1123_date, ne_asctime_parse,\n\tne_rfc1036_parse): Added ne_ prefix.\n\nThu Mar 22 14:03:12 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* base64.c (ne_base64): Renamed from base64.\n\nTue Mar 20 20:34:44 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* dav_props.c (make_elms): Don't request UTF-8 decoding of\n\tproperty values.\n\nTue Mar 20 20:33:39 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* string_utils.c (ne_utf8_decode): New function.\n\nMon Mar 19 22:08:45 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_basic.c (get_callback): Removed function.  (http_get,\n\thttp_read_file, http_post): Use callbacks directly rather than\n\tindirectly through get_callback.\n\nMon Mar 19 21:55:19 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_request.c (notify_status, http_set_status,\n\thttp_set_progress): New functions: request status and progress\n\tcallbacks.  (open_connection, lookup_host): Use notify_status to\n\ttrigger status callbacks, and register socket progress callbacks.\n\nMon Mar 19 21:53:07 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* socket.c (sock_register_notify): Removed function.\n\t(sock_connect_u): Renamed to sock_connect.\n\t(sock_register_progress): Per-socket progress callbacks rather\n\tthan global ones.  (sock_call_progress): Take socket argument.\n\t(all callers changed).\n\nMon Mar 19 21:52:50 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* socket.c (sock_get_version): New function.\n\nMon Mar 19 13:59:21 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* dav_props.c (propfind): Destroy the handler.\n\nMon Mar 19 13:36:55 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* dav_props.c (dav_propnames): New function.\n\nWed Mar 14 22:42:12 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_request.h (http_begin_request, http_end_request,\n\thttp_read_response_block): New functions.\n\t(http_request_dispatch): Reimplemented using new caller-pulls\n\tinterface.\n\nWed Mar 14 22:20:38 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_auth.c (ah_post_send): If authentication fails (i.e. bad\n\tcredentials), clean the session details.\n\nWed Mar 14 20:46:55 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_auth.c: Retry the request simply if it has not been tried\n\tbefore with authentication details, otherwise, fail on 40[17].\n\nWed Mar 14 20:12:52 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_request.c (open_connection): Make sure to close the\n\tconnection, and return HTTP_CONNECT if the SSL negotiation fails.\n\nTue Mar  6 18:37:43 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_alloc.c (ne_strndup): Allocate n+1 bytes not 'n' (Kai\n\tSommerfeld).\n\nMon Mar  5 01:05:31 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_request.c: Moved local sbuffer variables of\n\thttp_request_dispatch into http_req members 'reqbuf' and\n\t'respbuf'.  (build_request): Return a const char * of the request.\n\t(send_request): Call build_request directly, use req->respbuf.\n\t(http_request_dispatch): Don't call build_request.  Removed 'goto'\n\texception handling (hoorah).  (http_request_create,\n\thttp_request_destroy): Create and destroy reqbuf and respbuf here.\n\nMon Mar  5 00:43:40 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_request.c (http_set_request_body_stream): Set\n\treq->body_size and Content-Length header here: return success\n\tvalue.  (http_set_request_body_buffer): Likewise (but no return\n\tvalue).  (get_request_bodysize): Removed function.\n\t(build_request): Add Content-Length: 0 header if no request body.\n\nMon Mar  5 00:27:24 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_auth.c (http_forget_auth): New function.\n\nMon Mar  5 00:25:15 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_request.c (http_request_hook_private): Renamed from\n\thttp_get_hook_private.  (http_session_hook_private): New function.\n\n\t* dav_locks.c (dav_lock_using_resource, dav_lock_using_parent):\n\tRenamed simiarly.\n\nSun Mar  4 23:12:12 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_auth.c: Moved per-request state into struct auth_request.\n\t(request_digest): Take struct auth_request argument.  (free_auth):\n\tNew function.  (http_add_hooks): Pass free_auth as cleanup\n\tfunction for auth session.\n\nSun Mar  4 23:08:46 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_redirect.c (auto_redirect): Auto-redirect OPTIONS requests.\n\t(free_redirect): New function.  (http_redirect_register): Pass\n\tcleanup function.\n\nSun Mar  4 23:07:01 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* dav_locks.c (dav_lock_unregister): Removed function.\n\t(free_locks): New function.  (dav_lock_register): Pass free_locks\n\tas cleanup function for hooks.\n\nSun Mar  4 22:54:57 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_request.h (http_add_hooks): Added fourth argument to\n\tregister a cleanup function for the cookie.\n\nSun Mar  4 19:53:03 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_auth.c (request_digest): Use an sbuffer to create the\n\theader value.\n\nSun Mar  4 19:44:18 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_auth.c: Remove namespace protection for private\n\tfunctions. s/http_auth/auth/g.\n\nSun Mar  4 19:39:13 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_auth.c (ah_pre_send): Increase attempt counter here, ...\n\t(ah_post_send): instead of here.\n\nSun Mar  4 18:40:03 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_request.c (http_request_dispatch): Simplify post_send hook\n\tinvocation: run them until one doesn't return HTTP_OK. Don't run\n\tpre_send hooks here.  Loop while a hook returns HTTP_RETRY.\n\t(build_request): Run pre_send hooks here.\n\n\t* http_request.c (read_response_body): Call\n\tnormalize_response_length here.\n\nSun Mar  4 18:12:26 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\tRe-implemented HTTP authentication using generic hooks interface.\n\n\t* http_auth.c: Added http_auth.h.  (http_auth_init,\n\thttp_auth_set_creds_cb, http_auth_new_request,\n\thttp_auth_request_header): Removed functions, merged into new\n\thooks code.  (ah_create, ah_post_send, ah_pre_send, ah_use_body,\n\tah_destroy): New functions.  (auth_body_reader,\n\thttp_set_server_auth, http_set_proxy_auth): Moved over from\n\thttp_request.c and redone for hooks interface.\n\n\t* http_request.c (http_set_server_auth, http_set_proxy_auth,\n\tgive_creds, auth_body_reader): Moved to http_auth.c.\n\t(http_accept_always): Renamed from always_accept_response and made\n\tpublic.  (http_request_create, build_request,\n\thttp_request_dispatch): Removed authentication code.\n\nTue Feb 27 19:49:42 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* dav_props.c (set_body): Remove UTF-8 encoding again.\n\nMon Feb 26 22:38:41 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\tPatch from Kai Sommerfeld to remove URI escaping from inside neon.\n\t\n\t* dav_207.c (end_element): Don't unescape href elements.\n\n\t* http_request.c (http_request_create): Don't escape Request-URI.\n\n\t* dav_basic.c (copy_or_move): Don't escape destination URI.\n\nMon Feb 26 21:44:56 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* dav_props.c (set_body): UTF-8 encode the property name and\n\tvalue.  (make_elms): Request UTF-8 decoding of property values.\n\nMon Feb 26 21:40:14 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* hip_xml.c: Do perform UTF-8 decoding when using libxml.\n\t(char_data): Fix UTF-8 decoding bug where the byte after a\n\tmulti-byte encoded sequence would be skipped.\n\nSun Feb 25 20:04:05 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* string_utils.c (ne_utf8_encode): New function.\n\nSun Feb 25 19:52:01 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ne_alloc.c (ne_realloc): New function.\n\nSun Feb 25 17:00:32 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* Makefile.in (all): Rename NEON_IS_BUNDLED to NEON_BUILD_BUNDLED.\n\nSun Feb 25 16:52:43 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* Makefile.in (all): Build according to NEON_IS_BUNDLED.\n\nFri Feb 23 23:38:10 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* Makefile.in: Fix deps: neon_config.h has gone.\n\nFri Feb 23 22:57:47 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* dav_props.c (dav_simple_propfind): Support a NULL 'props'\n\targument to do an allprop request, as per the advertising\n\tliterature.  Register a catch-all handler in this case.\n\nFri Feb 23 22:16:42 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_request.c (http_session_destroy): Free up hooks list.\n\nThu Feb 22 21:54:36 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_request.h (http_add_hooks): Make request_hooks 'const'.\n\nThu Feb 15 08:36:56 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_request.c (read_response_body): Accept SOCK_CLOSED as\n\tend-of-response if we don't have a Content-Length (and not\n\tchunked). (Kai Sommerfeld).\n\nThu Feb 15 08:36:23 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_request.c (add_fixed_headers): Don't add the Host header\n\there.  (http_request_dispatch): Add it here instead.\n\n\t* http_request.c (set_hostinfo): Dup the hostname.\n\t(http_session_destroy): Free the hostname.  (Kai Sommerfeld).\n\nThu Feb 15 08:35:49 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_private.h: Make hostname in struct host_info char *. (Kai\n\tSommerfeld).\n\nThu Feb 15 08:08:50 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_redirect.h: Add C++ header-inclusion safety macros (Kai\n\tSommerfeld <kai.sommerfeld@germany.sun.com>).\n\nWed Feb 14 23:37:57 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_request.c (read_response_body): Use a size_t for readlen,\n\tas read_response_block requires.\n\nWed Feb 14 23:25:44 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_auth.c (request_digest): Fix incorrect signed-ness of\n\tbuffer.\n\nWed Feb 14 23:22:13 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* uri.h, string_utils.h: Comment-out tokens after #endif.\n\nSun Feb  4 14:36:11 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_redirect.c (post_send): Prototype change.\n\nSun Feb  4 14:31:42 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* socket.c: Added key_prompt, key_userdata, key_file to\n\tnssl_context.  (sock_set_key_prompt, key_prompt_cb): New\n\tfunctions.  (sock_make_secure): Set ctx->key_file to private key\n\tfilename.\n\nSun Feb  4 13:31:44 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_request.h: Make http_status argument of post_send a const\n\tpointer.\n\nSun Feb  4 10:38:12 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_request.c (set_sockerr): Only use the socket error if it is\n\tNULL, else print generic \"something went wrong\"-type error\n\tmessage.\n\nSun Feb  4 10:29:37 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* socket.c (sock_set_client_cert): Call SSL_CTX_check_private_key\n\tto ensure that the cert and private key match.\n\nSun Feb  4 10:28:02 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* socket.c (sock_make_secure): In error cases after SSL_connect\n\tsucceeds, call SSL_shutdown and assign sock->ssl = NULL before\n\treturning.\n\nSat Feb  3 18:33:56 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* socket.c (sock_close): Call SSL_shutdown before close()'ing the\n\tfd.\n\nSat Feb  3 18:30:48 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* socket.c: Store an default SSL_CTX in nsocket, to be used when\n\tno nssl_context is supplied.  (create_socket): Create default\n\tSSL_CTX (sock_close): Free it here.  (sock_make_secure): Use it\n\there.\n\nSat Feb  3 15:52:15 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* socket.c (sock_set_client_cert): New function.\n\nSat Feb  3 15:48:51 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* socket.c: Rejig of nssl_context handling.  An nssl_context is\n\tnow really a wrapper for an SSL_CTX.  (sock_create_ssl_context):\n\tCreate the SSL_CTX here.  (sock_disable_tlsv1, sock_disable_sslv2,\n\tsock_disable_sslv3): Set the SSL_CTX option directly.\n\t(sock_make_secure): Create an SSL_CTX if no nssl_context is\n\tsupplied, otherwise use SSL_CTX from nssl_context.\n\nSun Jan 28 13:52:03 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http_utils.c (neon_version_minimum): New function.\n\nSun Jan 28 10:37:28 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* neon_config.h.in: Removed file.\n\n\t* http_request.c, http_utils.c: Don't include neon_config.h.\n\nSat Jan 27 22:52:37 2001  Joe Orton  <joe@light.plus.com>\n\n\t* socket.c: Use closesocket() as NEON_CLOSE (Markus Fleck\n\t<fleck@isoc.de>).\n\nSat Jan 27 22:35:16 2001  Joe Orton  <joe@light.plus.com>\n\n\t* hip_xml.c: Add 'char_data' as libxml cdataBlock handler.\n\nTue Jan 23 23:17:00 2001  Joe Orton  <joe@light.plus.com>\n\n\t* neon_config.h.in: Renamed from neon_config.h.  Define\n\tNEON_VERSION_MAJOR and NEON_VERSION_MINOR too: all picked up from\n\tthe NEON_VERSIONS macro.\n\nSun Jan 21 22:07:34 2001  Joe Orton  <joe@light.plus.com>\n\n\t* string_utils.c (ne_concat): New function.\n\nThu Jan 18 22:25:34 2001  Joe Orton  <joe@light.plus.com>\n\n\t* ne_alloc.h: Added ne_oom_callback.\n\n\t* ne_alloc.c: Added DO_MALLOC macro to do the malloc and oom\n\tcallback test.  (ne_malloc): Use DO_MALLOC.  (ne_strdup,\n\tne_calloc, ne_strndup): Reimplement using DO_MALLOC rather than\n\tcalling ne_malloc().\n\nTue Jan 16 20:16:35 2001  Joe Orton  <joe@light.plus.com>\n\n\t* neon_config.h: Bumped version to 0.10.1.\n\nTue Jan 16 20:14:40 2001  Joe Orton  <joe@light.plus.com>\n\n\t* http_request.c (http_session_create): Default expect-100 support\n\tto OFF.\n\nMon Jan 15 22:59:33 2001  Joe Orton  <joe@light.plus.com>\n\n\t* neon_config.h: Bumped version to 0.10.0.\n\nMon Jan 15 22:58:04 2001  Joe Orton  <joe@light.plus.com>\n\n\t* dav_basic.c (dav_simple_request): Use dav_207_ignore_unknown.\n\nSun Jan 14 22:52:31 2001  Joe Orton  <joe@light.plus.com>\n\n\t* dav_props.c (propfind): Call dav_207_ignore_unknown.\n\nSun Jan 14 22:49:06 2001  Joe Orton  <joe@light.plus.com>\n\n\t* dav_207.c: Don't handle unknown elements in normal handler.\n\t(ignore_cc, dav_207_ignore_unknown): New functions, for ignoring\n\tany unknown elements in the parse.\n\nSun Jan 14 21:53:00 2001  Joe Orton  <joe@light.plus.com>\n\n\t* hip_xml.c: Renamed 'handlers' back to top_handlers.\n\t(push_handler): Now, p->root->handlers points to BASE of stack,\n\tp->top_handlers points to TOP of stack.  (hip_xml_destroy):\n\tChanged to start from new BASE of stack.\n\nSun Jan 14 10:50:09 2001  Joe Orton  <joe@light.plus.com>\n\n\t* http_request.c (http_session_server): Do perform the DNS lookup\n\tif we have a proxy_decider function, since that means we MIGHT\n\tneed to know the IP address of the origin server.\n\t(http_request_create): Pass the real scheme back to the proxy\n\tdecider callback.\n\nWed Jan 10 22:43:16 2001  Joe Orton  <joe@light.plus.com>\n\n\t* Makefile.in: Rename OBJ_EXT to NEON_OBJEXT.  Remove\n\tNEON_INTERFACE_VERSION, use NEON_LINK_FLAGS instead.\n\nWed Jan 10 22:02:02 2001  Joe Orton  <joe@light.plus.com>\n\n\t* dav_locks.c (create_private): New function.\n\t(dav_lock_discover): Switch to using new dav_propfind_set_complex\n\tAPI.\n\nWed Jan 10 21:59:36 2001  Joe Orton  <joe@light.plus.com>\n\n\t* dav_props.h (dav_propfind_set_complex): Switch the\n\t'sizeof_private' argument for a callback 'creator': the return\n\tvalue of this callback is used as the 'private' field for the\n\tcurrent resource.\n\nMon Jan  8 22:09:55 2001  Joe Orton  <joe@light.plus.com>\n\n\t* dav_locks.h (dav_lock_result): Re-order arguments.  Make lock\n\tobject const.\n\t\n\t* dav_locks.c (dav_lock_copy): New function.  (discover_results):\n\tSet lock->uri given href for current results.  Free lock object\n\tafter passing to results.\n\nSun Jan  7 21:55:14 2001  Joe Orton  <joe@light.plus.com>\n\n\t* dav_locks.c (dav_lock): Destroy XML parser after use.  Remove\n\thandling of Lock-Token header: it wasn't used and it leaked.\n\nSun Jan  7 19:58:29 2001  Joe Orton  <joe@light.plus.com>\n\n\t* dav_props.c (free_propset): Free the property values, and the\n\tresult set URI too.\n\nSun Jan  7 16:58:19 2001  Joe Orton  <joe@light.plus.com>\n\n\t* http_request.c (read_response_block): Fix handling of\n\tSOCK_CLOSED from sock_read as end-of-connection.\n\nSat Jan  6 15:02:57 2001  Joe Orton  <joe@light.plus.com>\n\n\t* hip_xml.c (struct hip_xml_parser): Renamed 'top_handlers' to\n\t'handlers' in hip_xml_parser.  (push_handler): New function.\n\t(hip_xml_push_handler, hip_xml_push_mixed_handler): Use\n\tpush_handler.\n\n\t* hip_xml.c (find_handler): Begin the search for a new handler\n\tfrom the handler of the current (parent) element, and work up the\n\tstack.\n\nSat Jan  6 11:15:17 2001  Joe Orton  <joe@light.plus.com>\n\n\t* hip_xml.c (find_handler): Display error message for unknown XML\n\telement as 'elmname (in nspace)' rather than 'nspace:elmname'\n\tsince the latter produces confusing errors like\n\t'DAV::displayname'.\n\nWed Jan  3 21:34:44 2001  Joe Orton  <joe@light.plus.com>\n\n\t* Makefile.in: Hard-code top_builddir as '..' (possibly wrong, but\n\ttrue for all neon apps so far).  Remove INCLUDES, now unused.  Add\n\ttop_srcdir.\n\nFri Dec 22 22:51:27 2000  Joe Orton  <joe@light.plus.com>\n\n\t* dav_props.c: Added 'has_props' field to propfind_handler struct.\n\t(set_body): Only add leading 'prop' element if has_props is not\n\tset.  Set has_props.  Don't add trailing </prop> element here.\n\t(dav_propfind_named): ... add it here instead.\n\t(dav_propfind_set_complex, dav_propfind_set_flat): New set_body\n\tinterface.\n\nFri Dec 22 21:10:39 2000  Joe Orton  <joe@light.plus.com>\n\n\t* socket.c (sock_transfer): Don't use NEON_READ here, this is\n\tfor reading from a non-socket fd.\n\nWed Dec 20 00:19:34 2000  Joe Orton  <joe@light.plus.com>\n\n\t* neon_config.h: Bumped version to 0.9.1.\n\nWed Dec 20 00:19:09 2000  Joe Orton  <joe@light.plus.com>\n\n\t* dav_props.c (free_propset): Don't free the private structure,\n\tmake this the caller's responsibility.\n\nWed Dec 20 00:12:36 2000  Joe Orton  <joe@light.plus.com>\n\n\t* dav_props.c (end_propstat): Rename propstat argument to\n\t'pstat_v' to kill warnings.\n\nTue Dec 19 23:42:39 2000  Joe Orton  <joe@light.plus.com>\n\n\t* dav_props.c (start_response): Zero-out the private structure on\n\tcreation.\n\nTue Dec 19 22:54:06 2000  Joe Orton  <joe@light.plus.com>\n\n\t* http_request.c (read_response_block): Rename local variable\n\t'socket' to 'sock'.\n\nTue Dec 19 22:52:56 2000  Joe Orton  <joe@light.plus.com>\n\n\t* http_request.h: Rename argument from 'stat' in post_send\n\tdefinition.\n\nTue Dec 19 22:52:32 2000  Joe Orton  <joe@light.plus.com>\n\n\t* http_utils.h: Add 'const' to char * argument.\n\nTue Dec 19 22:19:28 2000  Joe Orton  <joe@light.plus.com>\n\n\t* neon_config.h: Bumped version to 0.9.0.\n\nTue Dec 19 22:12:19 2000  Joe Orton  <joe@light.plus.com>\n\n\t* Makefile.in: New file.\n\nTue Dec 19 22:07:50 2000  Joe Orton  <joe@light.plus.com>\n\n\t* Makefile.incl: Removed file.\n\nTue Dec 19 22:06:06 2000  Joe Orton  <joe@light.plus.com>\n\n\t* dav_locks.c (dav_lock_discover): New callback-based lock\n\tdiscovery interface.  Re-implemented using new propfind interface.\n\nTue Dec 19 21:22:43 2000  Joe Orton  <joe@light.plus.com>\n\n\t* dav_props.h: Replace old dav_propfind_* interface with better\n\tone.  (dav_simple_propfind): Renamed from dav_get_props.\n\t(dav_propfind_current_private, dav_propfind_set_complex,\n\tdav_propfind_set_flat): New functions.\n\t(dav_propfind_get_current_resource): Removed function.\n\t(dav_propfind_named, dav_propfind_allprop): Change second argument\n\tto be the results callback.\n\n\t* dav_props.c: Replace implementatino of old interface with new\n\tone.  (dav_simple_propfind): Re-implemented on top of new\n\tall-singing all-dancing dav_propfind_* interface.\n\nSun Dec 17 18:24:50 2000  Joe Orton  <joe@light.plus.com>\n\n\t* dav_props.c: Add dav_get_props, and all its auxiliaries.\n\nSun Dec 17 15:43:55 2000  Joe Orton  <joe@light.plus.com>\n\n\t* dav_props.c (propfind): Destroy the request after calling\n\thttp_get_status.\n\nSun Dec 17 18:04:58 2000  Joe Orton  <joe@light.plus.com>\n\n\t* hip_xml.c (find_handler): Allow using NULL as name and nspace in\n\tHIP_ELM_unknown elements.\n\nSun Dec 17 18:03:03 2000  Joe Orton  <joe@light.plus.com>\n\n\t* dav_207.c (check_context): Don't handle the unknown element when\n\tit is a child of the prop element, this prevents handling allprop\n\tresponses.\n\nThu Dec 14 21:48:06 2000  Joe Orton  <joe@light.plus.com>\n\n\t* neon_config.h: Bumped version to 0.8.0.\n\nThu Dec 14 21:43:31 2000  Joe Orton  <joe@light.plus.com>\n\n\t* dav_basic.c, dav_locks.c, dav_props.c (everywhere): Changed to\n\tnew response-status interface, and _class->klass change.\n\nThu Dec 14 21:37:38 2000  Joe Orton  <joe@light.plus.com>\n\n\t* http_request.c (http_get_status): Add new response-status\n\tinterface.\n\nThu Dec 14 21:30:25 2000  Joe Orton  <joe@light.plus.com>\n\n\t* http_basic.c (everywhere): Use new status interface.\n\nThu Dec 14 21:25:03 2000  Joe Orton  <joe@light.plus.com>\n\n\t* http_private.h: Made http_status pointer in http_req a declared\n\tobject.\n\n\t* http_request.h: Removed passing status pointer to\n\thttp_request_dispatch.\n\n\t* http_request.c (everywhere): Removed passing extra http_status *\n\tto auxiliaries, use req->status instead.  Renamed '_class' to\n\t'klass' everywhere.\n\t\nThu Dec 14 21:15:54 2000  Joe Orton  <joe@light.plus.com>\n\n\t* http_utils.h: Renamed '_class' member of http_status to 'klass'.\n\t(http_parse_statusline): Change accordingly.\n\nWed Dec 13 23:00:23 2000  Joe Orton  <joe@light.plus.com>\n\n\t* socket.c: Changes for pre-BONE BeOS (David Reid\n\t<dreid@jetnet.co.uk>).\n\nWed Dec 13 21:29:36 2000  Joe Orton  <joe@light.plus.com>\n\n\t* uri.c (ESCAPE): Explicitly cast the character to const unsigned\n\tint.  (uri_abspath_escape): Make 'pnt' a normal const char *.\n\nWed Dec 13 21:17:31 2000  Joe Orton  <joe@light.plus.com>\n\n\t* http_request.c: Remove netinet/in.h include, add limits.h\n\tinclude. (Peter Boos) (read_response_block): Make readlen a size_t\n\t(David Reid).\n\nWed Dec 13 21:08:08 2000  Joe Orton  <joe@light.plus.com>\n\n\t* ne_alloc.h [WIN32]: Include stdlib.h. (Peter Boos)\n\nWed Dec 13 20:54:27 2000  Joe Orton  <joe@light.plus.com>\n\n\tPatches from Peter Boos and David Reid for Win32 and\n\tBeOS changes respectively:\n\t\n\t* socket.c: Add NEON_READ, NEON_WRITE, NEON_CLOSE macros to use\n\tsend/recv/closesocket for BeOS, send/recv/close for Win32,\n\twrite/read/close otherwise.  Include WinSock2.h in Windows.  Add\n\tarpa/inet.h check. (sock_read, sock_write): Use the NEON_ macros.\n\t(sock_connect, sock_close): Use NEON_CLOSE. (sock_init): Winsock\n\tinitialization.  (sock_exit) Winsock cleanup.  (sock_fullwrite):\n\tUse size_t rather than ssize_t for 'sent'.  (sock_connect,\n\tsock_connect_u): Make 'port' parameter an unsigned short int.\n\nWed Dec 13 20:42:18 2000  Joe Orton  <joe@light.plus.com>\n\n\t* http_basic.c (clength_hdr_handler): Use an off_t for len, to\n\tavoid comparison with size_t.\n\nWed Dec 13 20:38:59 2000  Joe Orton  <joe@light.plus.com>\n\n\t* hip_xml.c (char_data): Use an 'int' for wslen, avoid comparison\n\tbetween size_t (which is signed) and int (which [is|might be?]\n\tunsigned).\n\nWed Dec 13 20:29:12 2000  Joe Orton  <joe@light.plus.com>\n\n\t* nsocket.h [WIN32]: Use Windows headers rather than Unixy ones.\n\t(sock_exit): New function.\n\nWed Dec 13 20:21:22 2000  Joe Orton  <joe@light.plus.com>\n\n\t* string_utils.c, string_utils.h, uri.h: Includes change (Peter\n\tBoos).\n\nWed Dec 13 20:20:09 2000  Joe Orton  <joe@light.plus.com>\n\n\t* http_auth.c (http_auth_response_body): Don't make\n\tinline. Includes change.  (both by Peter Boos).\n\nWed Dec 13 20:18:38 2000  Joe Orton  <joe@light.plus.com>\n\n\t* uri.c (uri_unescape): Cast strtol return to (char). Includes\n\tchange as below (both by Peter Boos).\n\nWed Dec 13 20:07:38 2000  Joe Orton  <joe@light.plus.com>\n\n\t* base64.c, dates.c, dates.h, dav_207.c, dav_207.h, dav_basic.h,\n\tdav_locks.h, hip_xml.h, http_auth.h, http_basic.h, http_cookies.c,\n\thttp_redirect.c, http_redirect.h, http_request.h, http_utils.c,\n\tmd5.c, ne_alloc.c: Use #include \"...\" rather than #include <...>\n\tfor neon headers. (Peter Boos <PediB@colorfullife.com>).\n\nThu Dec  7 21:45:02 2000  Joe Orton  <joe@light.plus.com>\n\n\t* socket.c (sock_read): Return zero immediately if a zero count\n\tparameter is passed, following SUSv2 semantics.\n\nThu Dec  7 21:41:36 2000  Joe Orton  <joe@light.plus.com>\n\n\t* nsocket.h (sock_readfile_blocked): Define an interface, allow\n\ttaking -1 as the length parameter.  Only return SOCK_CLOSED if\n\tlength == -1 is NOT passed.\n\nSun Nov 26 09:46:53 2000  Joe Orton  <joe@light.plus.com>\n\n\t* nsocket.h: Fix use of 'socket' in function prototypes.\n\nSun Nov 19 00:29:48 2000  Joe Orton  <joe@light.plus.com>\n\n\t* nsocket.h: Increase read timeout to 120 seconds.\n\nSun Nov  5 14:42:46 2000  Joe Orton  <joe@light.plus.com>\n\n\t* dav_locks.c: Fix element id's (fixes segfault when using locks).\n\nThu Oct 26 22:28:17 2000  Joe Orton  <joe@light.plus.com>\n\n\t* socket.c (sock_peek): Return SOCK_CLOSED if recv() returns zero.\n\nThu Oct 26 22:24:14 2000  Joe Orton  <joe@light.plus.com>\n\n\t* socket.c (sock_block): Return \"got data\" if SSL_pending\n\tindicates data pending.  Otherwise select on socket as normal.\n\nThu Oct 26 22:15:14 2000  Joe Orton  <joe@light.plus.com>\n\n\t* socket.c (sock_readline, sock_peek): Check whether SSL\n\tconnection has been closed if SSL_peek returns 0 (thanks to Jeff\n\tCostlow <j.costlow@f5.com>).\n\nThu Oct 14 19:57:31 2000  Joe Orton  <joe@light.plus.com>\n\n\t* Makefile.incl: Fix spurius backslash at line 69 (thanks to \n\tDirk Bergstrom <dirk@juniper.net>).\n\nSat Oct 14 19:51:44 2000  Joe Orton  <joe@light.plus.com>\n\n\t* dav_basic.c (copy_or_move): Use http_get_scheme rather than\n\thard-coding \"http\".\n\n2000-10-02  Joe Orton  <joe@light.plus.com>\n\n\t* http_request.c (http_get_scheme): New function.\n\nTue Oct 10 19:56:42 2000  Joe Orton  <joe@light.plus.com>\n\n\t* neon_config.h: Bumped version to 0.7.5.\n\nSat Oct  7 19:26:58 2000  Joe Orton  <joe@light.plus.com>\n\n\t* neon_config.h: Bumped version to 0.7.4.\n\nSat Oct  7 19:19:37 2000  Joe Orton  <joe@light.plus.com>\n\n\t* http_auth.c (request_digest): Quote algorithm and qop parameters\n\tin digest header.\n\nSat Oct  7 19:15:29 2000  Joe Orton  <joe@light.plus.com>\n\n\t* socket.c (sock_connect_u): Don't leak the fd if connect fails\n\t(David Sloat).\n\nSat Sep 16 16:49:57 2000  Joe Orton  <joe@light.plus.com>\n\n\t* hip_xml.h: Add 'HIP_ELM_UNUSED', defining lowest element ID\n\twhich should be used.\n\n\t* hip_xml.c, hip_xml.h (hip_xml_push_handler,\n\thip_xml_push_mixed_handler): Renamed from hip_xml_add_handler /\n\thip_xml_add_mixed_handler to reflect stack-like usage of handlers.\n\t'handlers' field of hip_xml_parser renamed to top_handler for same\n\treason (globally search'n'replaced).\n\n\t* hip_xml.h: Documentation update.\n\t\nThu Sep 14 22:37:33 2000  Joe Orton  <joe@light.plus.com>\n\n\t* http_auth.c (request_digest): Quote qop= value, fixes\n\tIIS5 interop.\n\nThu Sep 14 00:40:04 2000  Joe Orton  <joe@light.plus.com>\n\n\t* socket.c (sock_connect_u): If connect() fails, close the socket\n\tbefore returning: thanks to David Sloat <d.sloat@f5.com>.\n\nTue Sep 12 20:08:40 2000  Joe Orton  <joe@light.plus.com>\n\n\t* http_request.c (read_response_headers): Remove redundant\n\ttolower().\n\nTue Sep 12 00:41:39 2000  Joe Orton  <joe@light.plus.com>\n\n\t* neon_config.h: Bumped version to 0.7.3.\n\nMon Sep 11 15:31:13 2000  Joe Orton  <joe@light.plus.com>\n\n\t* http_request.c, http_auth.c: Include snprintf.h if\n\tHAVE_SNPRINTF_H is defined.\n\nFri Sep  8 10:46:53 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* neon_config.h: Bumped version to 0.7.2.\n\nFri Sep  8 10:44:42 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* socket.c (sock_block): Return immediately if this is an SSL\n\tsocket.\n\nThu Sep  7 00:31:12 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* hip_xml.h: Correct order of hip_xml_validate_cb arguments in\n\tprototype (thanks to Greg Stein).\n\nThu Sep  7 00:27:29 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* dav_props.c (propfind): Don't destroy the handler after use.\n\t(dav_propfind_destroy): New function.\n\nThu Sep  7 00:08:45 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* Makefile.incl: Added targets for ne_alloc.o, string_utils.o,\n\turi.o, base64.o.\n\nTue Aug 15 21:53:53 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* neon_config.h: Bumped version to 0.7.1.\n\nTue Aug 15 21:16:34 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_request.c (http_request_create): Only add authentication\n\tresponse body callbacks if a supply-credentials callback has been\n\tset for the session.  (http_request_dispatch): Similarly for\n\tresponse header callbacks.\n\nMon Aug 14 09:28:38 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* neon_config.h: Bumped version to 0.7.0.\n\nMon Aug 14 09:23:54 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* string_utils.h (SBUFFER_CAST): New macro.\n\nMon Aug 14 09:13:05 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_private.h: Use a hash table for storing response header\n\thandlers.  Added response header 'catchers', which are passed ALL\n\tresponse headers.\n\n\t* http_request.c (http_add_response_header_handler): Place the\n\thandler in the correct hash bucket. (hdr_hash): New function.\n\t(http_add_response_header_catcher): New function.\n\t(http_request_destroy): Destroy the header catchers, and iterate\n\tover the hash table to destroy the handlers.\n\t(read_response_headers): Optimisation: hash and search for ':' in\n\ta single loop.  Remove another local variable.  Iterate through\n\tcatchers too.\n\nSun Aug 13 15:57:35 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* neon_config.h: Bumped version to 0.6.1.\n\nSun Aug 13 15:50:42 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_request.c (send_request): Only go through the loop at most\n\ttwice.\n\nSun Aug 13 15:49:52 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_redirect.c (destroy): Don't free the redirect structure.\n\nSat Aug 12 17:10:32 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* neon_config.h: Bumped version to 0.6.0.\n\nSat Aug 12 16:48:47 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_request.c (http_session_decide_proxy): New function.\n\t(http_request_create): Call proxy \"decider callback\" to determine\n\twhether to use the proxy server for a given request or not.\n\nSat Aug 12 16:39:10 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* Makefile.incl: Updated for http_private.h and\n\thttp_redirect.[ch].\n\nSat Aug 12 16:36:49 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_request.c: Removed data structure definitions.\n\n\t* http_private.h: New file, contains data structure definitions.\n\tInterface NOT exported.\n\nSat Aug 12 16:31:32 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_redirect.c (destroy): No return value.\n\nSat Aug 12 16:04:02 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_redirect.[ch]: First cut at HTTP redirect handling.\n\nSat Aug 12 11:05:13 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* neon_config.h: Bumped version to 0.5.1.\n\nSat Aug 12 02:04:15 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* dav_locks.c (dav_lock_using_resource, dav_lock_using_parent):\n\tPrevent segfault if locking is not in use.\n\nFri Aug 11 17:19:06 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* neon_config.h: Bumped version to 0.5.0.\n\nFri Aug 11 16:31:23 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_request.c (read_message_header): Take a buffer for storing\n\tcontinuation lines. (read_response_headers): No need to strip EOL\n\tsince read_message_header does this already.  Use one less\n\tvariable.\n\nFri Aug  4 22:12:04 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_request.c (send_request): Don't retry sending the request\n\tmore than once.\n\nWed Aug  2 11:08:31 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* ne_alloc.[ch]: Renamed from xalloc.[ch].\n\nWed Aug  2 02:15:32 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* socket.c (sock_transfer): Return SOCK_CLOSED, or set sock->error\n\tappropriately on read failure.\n\nTue Aug  1 13:04:27 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* socket.c, nsocket.h (sock_progress, sock_call_progress,\n\tsock_transfer, sock_readfile_blocked): Use 'off_t' not 'size_t' as\n\tfile size type.\n\nFri Jul 28 13:32:37 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* neon_config.h: Bumped version to 0.4.2.\n\nFri Jul 28 13:31:38 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_request.c (send_request): Fix sending request body after\n\tgetting 100-continue response.\n\nFri Jul 28 11:26:47 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* neon_config.h: Bumped version to 0.4.1.\n\nFri Jul 28 10:32:34 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* neon_config.h: Bumped version to 0.4.0.\n\nFri Jul 28 10:28:21 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_basic.[ch] (http_post): New function, from Sander Alberink\n\t<sander.alberink@cmg.nl>.\n\nThu Jul 27 18:55:49 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_utils.c (neon_debug): No conditional compilation for\n\tfunction body: compile it all regardless of whether debugging is\n\tenabled or not, to allow applications to be debugged regardless of\n\twhether debugging is compiled into the library or not.\n\nThu Jul 27 16:59:26 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_basic.c (clength_hdr_handler): Cast off_t to long int for\n\tprinting.\n\nTue Jul 25 18:14:15 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_request.c (read_message_header): Iterate over header\n\thandler list before placing zero-terminator at ':': if a handler\n\thas a NULL name field, pass it the entire header value.\n\nTue Jul 25 18:00:49 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_request.c (http_get_request_headers): New function.\n\nMon Jul 24 16:55:29 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* neon_config.h: Bumped version to 0.3.9.\n\nMon Jul 24 16:54:33 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_basic.h: Use 'off_t' in http_content_range.\n\n\t* http_basic.c (http_get_range): Cast range values to (long int)\n\tto prevent compiler warnings.\n\nThu Jul 20 20:03:30 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_request.[ch], socket.c, http_basic.c: Include nsocket.h not\n\tsocket.h.\n\nThu Jul 20 20:02:20 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_utils.c (version_string): Indicate which XML parser is\n\tsupported.\n\nThu Jul 20 20:01:12 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* nsocket.h: Renamed from socket.h.\n\nThu Jul 20 15:02:35 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_utils.c, socket.c, http_request.c: SSL_ENABLE renamaed to\n\tENABLE_SSL.\n\nThu Jul 20 12:20:13 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* md5.c, http_auth.h: Include neon_md5.h.\n\nThu Jul 20 12:19:23 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* neon_md5.h: Renamed from md5.h.\n\nWed Jul 19 22:33:46 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* dav_basic.c (dav_simple_request): Don't leak ctype.value.\n\nWed Jul 19 22:32:03 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* dav_207.c (check_context): Accept unknown elements.\n\nWed Jul 19 22:31:10 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* dav_locks.c (dav_lock_iterate): Allow passing func as NULL.\n\nWed Jul 19 22:26:13 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* socket.h (SOCKET_READ_TIMEOUT): Increase to 60.\n\nWed Jul 19 22:25:51 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* dav_locks.h: Include http_request.h.\n\nMon Jul 17 11:41:16 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* dates.c (asctime_parse, rfc1036_parse): Actually pass the string\n\tto sscanf (thanks to lclint).  (rfc1123_date): Check for gmtime()\n\treturning NULL.\n\nMon Jul 17 09:16:43 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* neon_config.h: Bumped version to 0.3.1.\n\nMon Jul 17 09:07:58 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* dav_locks.c: Include limits.h: thanks to Paul D'Anna.\n\nSun Jul 16 18:47:15 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* neon_config.h: Bumped version to 0.3.0.\n\nSun Jul 16 16:44:25 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* neon_i18n.c (neon_i18n_init) [ENABLE_NLS && NEON_IS_LIBRARY]:\n\tNew compilation conditions.\n\nSun Jul 16 16:41:12 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* neon_i18n.c: New file.\n\nSun Jul 16 16:15:02 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* string_utils.c (sbuffer_*): Change to assert postcondition\n\t(buf->used == strlen(buf->data) + 1).  (sbuffer_append): Fix\n\tbrokenness.\n\nSun Jul 16 16:11:05 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* socket.c (sock_transfer): Increase sum length written correctly.\n\nSun Jul 16 16:10:23 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_request.c (http_get_hook_private): New function.\n\nSun Jul 16 16:07:11 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* hip_xml.c (find_handler): Call validate_cb for any handler which\n\trecognizes the element.  Allow return codes\n\tHIP_XML_{VALID,INVALID,DECLINE} from validate_cb.  If DECLINE is\n\treturned, continue searching handlers until one returns\n\t(IN)VALID.  (start_element): Don't call validate_cb.\n\n\t* hip_xml.c (start_element, end_element): In collect mode, don't\n\tprint namespace prefix if present.\n\nSun Jul 16 15:30:19 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* dav_locks.[ch]: New file, code mainly taken from cadaver and\n\tadapted for neon HTTP request/response handling.\n\nSun Jul 16 15:28:25 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* dav_basic.c (copy_or_move, dav_move, dav_copy): Pass overwrite\n\tas parameter.\n\nSun Jul 16 15:26:24 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* uri.c (uri_compare): Fixed to only return equal if *shorter*\n\tstring has no trailing slash.\n\nSat Jul 15 20:14:07 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* dav_207.c (dav_207_get_current_response,\n\tdav_207_get_current_propstat): New functions.\n\n\t* dav_props.c (dav_propfind_get_current_resource): Implement using\n\tdav_207_get_current_response.\n\nSat Jul 15 17:36:37 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* xalloc.c (xcalloc): New function.\n\nSat Jul 15 14:11:14 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_utils.[ch] and elsewhere: Replace 'class' field of\n\thttp_status with '_class' to be C++-safe. (patch from Tom\n\tBednarz).\n\nThu Jul  6 18:48:52 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* dav_basic.c (copy_or_move): Escape the destination URI.\n\nThu Jul  6 18:45:51 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* dav_props.c (end_response): Added description parameter.\n\nThu Jul  6 18:43:14 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* dav_207.[ch] (end_element): Fix handling of responsedescription.\n\tAdd \"description\" parameter to dav_207_end_response callback, and\n\tpass the contents of responsedescription.\n\n\t* dav_basic.c (handle_error, end_response, end_propstat): Pass\n\tdescription and add to error string when present.\n\nTue Jul  4 11:43:03 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* dav_basic.c, dav_props.c, http_basic.c: Use\n\thttp_{add,print}_request_header rather than\n\thttp_get_request_header.\n\nTue Jul  4 11:41:00 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_request.[ch] (http_add_request_header,\n\thttp_print_request_header): New functions.\n\t(http_get_request_header): Removed function.\n\nMon Jul  3 21:50:40 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_request.c: Add basic support for TLS upgrade (RFC2817).\n\t(http_set_request_secure_upgrade, http_set_accept_secure_upgrade):\n\tNew functions.  (send_request): If upgrade is requested, and a 101\n\tresponse is received, negotiate the TLS connection.\n\t(add_fixed_headers): Add Upgrade header if necessary.\n\nMon Jul  3 21:46:00 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_request.c (send_request): Don't go into an infinite loop.\n\t(read_message_header): Simplyify checking for end-of-line.\n\nTue Jun 13 00:29:42 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_request.c (http_session_proxy, http_session_server): Allow\n\tcalling >1 time per session, to switch servers.  (send_request):\n\tOnly retry sending request once.\n\nMon Jun 12 21:50:41 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_request.c (http_add_hooks): New function.\n\nMon Jun 12 21:37:24 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_cookies.[ch]: Added basic cookies support.\n\nMon Jun 12 21:33:33 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* socket.c (sock_create_ssl_context, sock_destroy_ssl_context,\n\tsock_disable_tlsv1, sock_disable_sslv2, sock_disable_sslv3,\n\tsock_make_secure): Added nssl_context handling.\n\nMon Jun 12 21:29:52 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_request.c (http_request_dispatch, http_request_create,\n\thttp_request_destroy, http_set_request_body_buffer,\n\thttp_set_request_body_stream): Added hook support.\n\nMon Jun 12 21:04:00 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_request.c (http_set_secure): Store an nssl_context.\n\t(open_connection): Give the nssl_context.\n\nSun Jun 11 16:37:52 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* sslcerts.c: Import of SSL support from mutt, relicensed under\n\tthe LGPL for use in neon by the author, Tommi Komulainen\n\t<Tommi.Komulainen@iki.fi>.\n\nSun Jun 11 11:30:16 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_request.c (set_sockerr): Updated to use sock_get_error.\n\nSun Jun 11 11:29:29 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* uri.c (uri_parse): Allow scheme to be omitted.\n\nFri Jun  9 20:39:24 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* socket.c (sock_get_error): New function.  (sock_*): Set\n\tsock->error and SOCK_ERROR on error.\n\nMon May 29 16:32:46 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* uri.c (uri_abspath_escape): Allocate the exact amount of memory\n\tneeded.\n\nMon May 29 15:53:33 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* dav_basic.c (dav_simple_request): Correct invalid XML logic.\n\nMon May 29 15:52:08 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* socket.c (create_sock, sock_accept, sock_get_fd): New\n\tfunctions.  (sock_connect_u): Use create_sock.\n\nSun May 28 21:00:37 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_utils.c (neon_version_string): New function.\n\nSun May 28 19:36:45 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* socket.c (sock_connect_u): Zero out allocated nsocket object.\n\nThu May 25 01:27:04 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* *.h: Include other neon headers with <braces>.\n\nThu May 25 01:02:12 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* dav_props.c: Include stdlib.h for 'free'.\n\nWed May 24 20:15:08 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_request.c (read_message_header): Return HTTP_RETRY if more\n\theaders to read, HTTP_OK on end-of-headers.\n\t(read_response_headers): Changed accordingly.\n\nWed May 24 19:56:29 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_request.c (send_request_body): Return a SOCK_* code.\n\t(send_request): Re-send request if socket has been closed (due to\n\tpersistent connection timeout).\n\nWed May 24 19:00:01 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* hip_xml.c (find_element): Fix unknown element handling.\n\nTue May 23 19:12:26 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* dav_props.c (propfind): Destroy the request body sbuffer after\n\tuse.\n\nTue May 23 15:43:42 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* socket.c (sock_make_secure) [SSL_ENABLE]: Conditionally compile\n\tSSL code. [!SSL_ENABLE]: Return failure.  (sock_close)\n\t[SSL_ENABLE]: Conditionally compile SSL code.\n\nTue May 23 15:37:53 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_request.c (http_session_create): Renamed from\n\thttp_session_init.  (http_session_destroy): Renamed frmo\n\thttp_session_finish.\n\nSun May 21 23:50:58 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_request.c (lookup_host): Use sock_name_lookup.\n\nSun May 21 23:40:39 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_request.c (http_request_create): Allow passing NULL uri\n\t(internal use only).  (http_set_secure): New function.\n\t(read_response_block, read_message_headers): Redone for new socket\n\tAPI.  (build_request): Moved http_auth_new_request calls here\n\t(from http_request_dispatch).  (send_request): Always call\n\topen_connection before sending the request.\n\t(read_message_header, read_response_headers): Looser check for\n\tempty line.  (normalize_response_length): Set response body length\n\tto zero on 2xx class response whilst in CONNECT, if no other\n\tresponse body length is given.  (http_request_dispatch): Don't\n\tclose the connection on a HTTP/1.0 2xx class response after a\n\tCONNECT request.  (proxy_tunnel): New function.\n\t(open_connection): Use an SSL connection where appropriate.  Use\n\tproxy_tunnel for tunnelling through a proxy.\n\nSun May 21 01:35:40 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* src/socket.c: Added 'nsocket' ADT for handling sockets.\n\t(sock_*): All changed to take 'nsocket *' argument rather than\n\tinteger file descriptor.  Added 'sock_secure_details' to\n\tsock_status enum.  (sock_make_secure, sock_init): New function.\n\t(sock_peek): Renamed from sock_recv.  (send_file_*, recv_file_*):\n\tRemoved functions.  (sock_name_lookup): Renamed from host_lookup.\n\t(sock_service_lookup): Renamed from get_tcp_port.  (sock_block,\n\tsock_read, sock_fullwrite, sock_peek, sock_readline): Added SSL\n\tsupport.  (sock_transfer): Use sock_fullwrite and sock_read.\n\nSun May 21 01:25:03 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_request.c (http_request_destroy): Free header handlers and\n\tbody readers.\n\nSun May 21 01:24:30 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* dav_props.h: Removed obsolte got_property callback type.\n\nSun May 21 01:23:59 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* dav_props.c (propfind): Free handler object after use.\n\nSun May 21 01:23:12 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* dav_207.c (dav_207_destroy): Don't try to free the 'response'\n\tfield.\n\nSat May 20 21:45:32 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_request.c: Changed 'te' enum of struct http_response to\n\t'is_chunked' boolean.\n\nSun May 14 01:00:42 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* dav_props.c (propfind): Return error on parse error.\n\nSun May 14 00:40:50 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* neon_config.h (NEON_VERSION): Bumped to 0.2.0.\n\nSat May 13 23:31:28 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* neon_defs.h (BEGIN_NEON_DECLS, END_NEON_DECLS): Added C++ safety\n\tmacros.\n\n\t* *.h: Surround with C++ safety macros.\n\nSat May 13 22:36:06 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* hip_xml.c (hip_xml_destroy): Free handlers.\n\nSat May 13 21:12:14 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* hip_xml.c (hip_xml_valid): Reversed return value.\n\nSat May 13 21:11:17 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_utils.c: Renamed http_debug_mask to neon_debug_mask,\n\tsimilarly neon_debug_stream.  (neon_debug_init): Renamed from\n\thttp_debug_init.\n\nSat May 13 19:24:40 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_utils.c: Initialize http_debug_mask to zero.\n\t(http_debug_init): New function.\n\n\t* http_utils.h: Fixed #ifdef DEBUGGING. Only define relevant\n\tDEBUG_* constants.\n\t\nSat May 13 19:23:34 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* neon_config.h: New file.\n\n\t* http_request.c: Include neon_config.h for NEON_VERSION.\n\nSat May 13 18:28:05 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* dav_props.c (dav_propfind_create): Create a hip_xml_parser, a\n\t207 parser, register start+end response handlers with 207 layer.\n\t(propfind): Fix allprop (Michael Sobolev).\n\n\t* dav_basic.c (dav_simple_request): Create and destroy\n\thip_xml_parser and 207 parser appropriately.\n\nSat May 13 18:24:49 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* dav_207.c: Now takes an externally-declared hip_xml parser\n\tpointer. (dav_207_create, dav_207_destroy): New functions.\n\t(dav_207_init, dav_207_init_with_handler, dav_207_parse,\n\tdav_207_error, dav_207_finish): Removed functions.\n\nSat May 13 17:32:45 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* hip_xml.[ch]: Rewritten to use opaque hip_xml_parser pointer.\n\tstruct hip_xml_handler and struct hip_xml_state removed from\n\texternal interface. struct hip_xml_elm * passed to startelm_cb and\n\tendelm_cb. (hip_xml_add_handler, hip_xml_valid, hip_xml_create,\n\thip_xml_destroy, hip_xml_set_error, hip_xml_get_error): New\n\tfunctions.  (hip_xml_init, hip_xml_destroy): Removed functions.\n\nSat May 13 13:43:56 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* neon.h: Removed.\n\nSat May 13 13:42:20 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* string_utils.h: Don't include config.h. (CONCAT*): Don't use\n\txmalloc, use malloc and abort manually.\n\nSat May 13 13:32:46 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_utils.h, dates.h, http_basic.h: Don't include config.h\n\nSat May 13 13:31:37 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* hip_xml.[ch], dav_207.c: Use HIP_ERR_SIZE for size of parser\n\terror string.\n\nSat May 13 13:30:40 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* Makefile.incl: Use obj_ext for object file extension.\n\nThu May 11 18:21:53 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* neon.h: Bumped version to 0.1.1.\n\nThu May 11 18:16:08 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_basic.c (get_to_fd): Fix short writes.\n\nWed May 10 19:22:01 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* neon.h: Bumped version to 0.1.0.\n\nWed May 10 17:46:48 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* uri.c (uri_parse, uri_free): New functions.\n\nWed May 10 17:43:37 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_basic.c (get_to_fd, http_get): Set error appropriately if\n\tfwrite() fails.\n\nWed May 10 14:25:38 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_utils.c (http_debug): New function.\n\nWed May 10 14:25:08 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_basic.c (get_callback): Call sock_call_progress.\n\nWed May 10 14:24:20 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* socket.c (sock_call_progress): New function.  (many places): Use\n\tit.\n\nWed May 10 14:22:48 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* uri.c (uri_has_trailing_slash): Moved from being inline.\n\nTue May  9 23:34:25 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* dav_props.c: Use handler as userdata for 207 callbacks, unified\n\thandler and context structures.  (start_prop, end_prop,\n\tstart_propelm, end_propelm): Removed functions.\n\t(dav_propfind_get_current_resource): New function.\n\nTue May  9 23:29:44 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* xalloc.[ch]: New files.\n\nTue May  9 23:05:47 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* dav_207.[ch]: Removed property and property element callbacks.\n\nTue May  9 23:01:00 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* dav_207.c: Use separate name/namespace for element names.\n\t(dav_207_init_with_handler): New function.  (end_element):\n\tUnescape URI in href element.\n\nTue May  9 19:54:07 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* dav_props.c (dav_propfind_allprop, dav_propfind_named, propfind,\n\tstart_response, end_response, start_prop, end_prop, start_propelm,\n\tend_propelm): New functions; PROPFIND support.\n\nTue May  9 19:45:17 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_request.c (build_request): Renamed from make_request.\n\nTue May  9 19:36:01 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* socket.[ch]: Added sock_block_reader.\n\nTue May  9 15:52:56 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* uri.c (uri_childof): Return false when parent is the same length\n\tas child.\n\nSun May  7 15:07:49 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* dav_207.c: Separated element namespace/names.\n\nTue May  2 16:40:59 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* hip_xml.[ch]: Added HIP_XML_UTF8DECODE flag.\n\nTue May  2 16:16:57 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* hip_xml.[ch]: Separate element name and namespace.\n\nMon May  1 00:21:24 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* dav_207.c (dav_accept_207): Moved function from dav_basic.c.\n\n\t* dav_basic.c (dav_accept_207, dav_parse_xml_block): Removed\n\tfunctions.\n\nSun Apr 30 22:47:47 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* dav_props.[ch]: Renamed dav_proppatch_item to\n\tdav_proppatch_operation.\n\nSun Apr 30 22:45:04 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* hip_xml.c (start_element): Clearer error message.\n\nSun Apr 30 19:12:07 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_basic.c (http_content_type_handler, dav_hdr_handler): New\n\tfunctions.  (http_options): Handle DAV header.\n\nSun Apr 30 18:08:53 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* dav_props.c (dav_proppatch): New function.\n\nSun Apr 30 18:05:55 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* dav_basic.c (handle_error): New function.  (end_response,\n\tend_propstat): Use it.  (dav_simple_request): Don't return the 207\n\terror string if we get all 2xx class status elements.\n\nSun Apr 30 16:56:41 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* dav_basic.c (dav_add_depth_header): New function.\n\nSun Apr 30 14:49:06 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* dav_207.c (start_element): Unknown element is only a property if\n\tthe parent is DAV:propstat.\n\nSun Apr 30 14:43:28 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* dav_basic.c (end_response, end_propstat): Only write error line\n\tif we have status information and the status is not a 424.\n\nSun Apr 30 14:28:23 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* dav_basic.h: Added DAV_DEPTH_*.\n\nSun Apr 30 12:47:50 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* dav_207.c (check_context): Allow (and ignore) unknown elements\n\tanywhere other than as the root.\n\nSun Apr 30 12:35:39 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* string_utils.h (ASC2HEX, HEX2ASC): New macros.\n\nSun Apr 30 12:34:37 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_auth.c [STANDALONE]: Removed. (everywhere): Switch to using\n\tmd5_to_ascii rather than md5_hexify.\n\nSun Apr 30 12:32:35 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_request.c (read_response_block): Fixed to return errors\n\tproperly and block length to parameter.  (read_response_body):\n\tChanged accordingly.\n\nSun Apr 30 12:29:45 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* hip_xml.c (friendly_name): New function, was PRETTY_NAME macro.\n\t(start_element, end_element): Fix COLLECT handling.\n\t(hip_xml_parse): Only write parse error if the document has not\n\talready been marked invalid.\n\nSun Apr 30 12:28:36 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* dav_basic.c (dav_simple_request): Rewritten for new 207\n\tinterface.  (start_response, end_response, end_propstat): New\n\tfunctions.\n\nSun Apr 30 12:27:52 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* dav_207.c (dav_207_error): Return the parser error.\n\nSat Apr 29 14:46:48 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* socket.c (sock_register_progress, sock_register_notify): New\n\tfunctions.  (everywhere): Use progress + notify callbacks rather\n\tthan fe_*.\n\nSat Apr 29 14:15:23 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* string_utils.c (md5_to_ascii, ascii_to_md5): New functions.\n\nSat Apr 29 13:55:39 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* hip_xml.c (hip_xml_init): abort() on out-of-memory.\n\nSat Apr 29 12:56:11 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* neon_i18n.h: New file.\n\nSat Apr 29 12:55:24 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* dav_207.[ch]: Re-implemented with sensible interface.\n\nFri Apr 28 14:56:01 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_auth.c (http_auth_request_header): Renamed from\n\thttp_auth_request.\n\n\t* http_request.c (make_request): As above.\n\nThu Apr 13 11:52:14 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_basic.c (http_put): Switched URI and stream arguments.\n\nThu Apr 13 09:51:21 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_request.c: Added user_agent field to session structure.\n\t(http_set_useragent): New function.  (add_fixed_headers): Only set\n\tuser-agent if sess->user_agent is set.\n\nThu Apr 13 09:49:32 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_request.c (lookup_host): New function, split from\n\tset_hostinfo.  (set_hostinfo): Doesn't perform DNS lookup.\n\t(http_session_server): Don't do a DNS lookup if we have a proxy.\n\nWed Apr 12 22:32:21 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_request.c (http_request_dispatch, http_request_create):\n\tStore auth header values in local variables rather than request\n\tstructure.  (http_request_create): Don't leak everything on error.\n\tHandle http_auth_challenge return value.\n\nWed Apr 12 22:30:06 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_basic.c (http_options): Pass server capabilites object,\n\tparse Server header to detect Apache/1.3.6 and before, indicating\n\tbroken 100-continue support.  (server_hdr_handler): New function.\n\nMon Apr 10 17:42:07 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* socket.c: Use 'int' for return values.\n\nMon Apr 10 17:41:40 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_auth.c (is_in_domain): Dummy implementation.\n\nMon Apr 10 17:40:21 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_request.c: Handle read() returning 0 when it shouldn't.\n\ti18n'ized error messages.\n\nMon Apr 10 14:45:09 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* dates.[ch], md5.[ch], base64.[ch]: Imported date handling\n\tutilities, MD5 checksum functions, and text->base64 converter.\n\nMon Apr 10 14:44:08 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* Makefile.incl: Dependancies updated for socket.[ch].\n\nMon Apr 10 14:43:36 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* dav_207.c: Replaced malloc() calls with xmalloc() calls.\n\nMon Apr 10 14:42:35 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_auth.c, uri.c, string_utils.h: Replaced malloc() calls with\n\txmalloc() calls.\n\nMon Apr 10 14:41:40 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* socket.[ch]: Imported socket handling utilities.\n\nMon Apr 10 14:36:03 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* string_utils.h (CONCAT*): Use xmalloc.\n\nMon Apr 10 13:52:17 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_request.c (set_sockerr): Added handling for socket errors.\n\nSat Apr  8 13:49:07 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* string_utils.[ch]: Imported string utilites.\n\nSat Apr  8 00:26:06 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_request.c (http_set_persist, http_set_expect100): New\n\tfunctions.\n\nSat Apr  8 00:25:37 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_basic.c (http_options): New function.\n\nFri Apr  7 13:01:35 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* neon.h: New file.\n\nFri Apr  7 12:59:40 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_request.c (normalize_response_length, read_response_body):\n\tNew functions.  (http_add_response_body_reader): Take a callback\n\tto determine whether the body reader wants to read the response\n\tbody.\n\nFri Apr  7 11:46:41 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_request.c (http_set_server_auth, http_set_proxy_auth): New\n\tfunctions.  (give_creds): Use supplied callbacks for\n\tauthentication.  (get_request_bodysize): Send Content-Length: 0 if\n\tno entity-body is being sent with a request.  (te_hdr_handler,\n\tconnection_hdr_handler): New functions.  (make_request): Don't use\n\tExpect: 100-continue if server is not HTTP/1.1 compliant.\n\t(read_message_header): Only read until HTTP_MAXIMUM_HEADER_LENGTH\n\tbytes of header have been read.  (read_response_headers): No\n\thard-coded header handling.  (http_request_create): Set\n\treq->method_is_head here.\n\nThu Apr  6 14:39:28 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* hip_xml.c [HIP_XML_DECODE_UTF8] (decode_utf8_double): New\n\tfunction.  (char_data) [HIP_XML_DECODE_UTF8]: Decode UTF-8.\n\nTue Mar 28 13:54:51 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* Makefile.incl: Imported makefile fragment.\n\nTue Mar 28 13:54:09 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_request.[ch] (http_get_error): New function.\n\nThu Mar 23 18:48:42 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* hip_xml.[ch]: Imported generic XML parsing layer.\n\n\t* dav_207.[ch]: Imported generic WebDAV 207 response handling.\n\t\n\t* dav_basic.[ch]: Imported/implemented DAV response handling and\n\tbasic Class 1 namespace methods.\n\nThu Mar 23 18:46:14 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_request.c (add_hooks, run_hooks, http_add_destroy_hook):\n\tAdding hooks support.  (add_fixed_headers): Send TE token in\n\tConnection header. Only send Keep-Alive header & token to pre-1.1\n\torigin servers (i.e., not proxies).\n\nThu Mar 23 12:49:01 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_auth.[ch], uri.[ch]: Imported HTTP authentication and URI\n\thandling modules.\n\nThu Mar 23 12:47:05 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_utils.c: Imported HTTP utility functions.\n\nThu Mar 23 12:44:38 2000  Joe Orton  <joe@orton.demon.co.uk>\n\n\t* http_request.[ch]: Implemented modular HTTP request handling.\n\n\t* http_basic.[ch]: Implemented basic HTTP methods GET, PUT, and\n\tPUT with If-Unmodified.\n\n"
  },
  {
    "path": "src/Makefile.in",
    "content": "#\n# neon source directory Makefile\n# \n# Use the NEON_NORMAL_BUILD or NEON_LIBTOOL_BUILD autoconf \n# macros to set up this Makefile correctly.\n#\n\nSHELL = @SHELL@\n\n# Installation paths\nprefix = @prefix@\nexec_prefix = @exec_prefix@\nlibdir = @libdir@\n\n# Build paths\nVPATH = @srcdir@\ntop_builddir = @top_builddir@\ntop_srcdir = @top_srcdir@\n\n# Toolchain settings.\nCC = @CC@\nAR = @AR@\nRANLIB = @RANLIB@\nLIBTOOL = @LIBTOOL@\n\n# Flags\nCPPFLAGS = @DEFS@ @CPPFLAGS@\nCFLAGS = @CFLAGS@\nLDFLAGS = @LDFLAGS@\nNEON_LINK_FLAGS = @NEON_LINK_FLAGS@\n# Note: don't substitute @LIBS@ in here; during a bundled\n# build of this directory, @LIBS@ may include -lneon.\nLIBS = @NEON_LIBS@ @NEON_LTLIBS@\n\nCOMPILE = $(CC) $(CPPFLAGS) $(CFLAGS)\nLT_COMPILE = $(LIBTOOL) --quiet --mode=compile --tag=CC $(COMPILE)\nLINK = $(LIBTOOL) --quiet --mode=link --tag=CC $(CC) -no-undefined $(LDFLAGS)\n\nNEON_BASEOBJS = ne_request.@NEON_OBJEXT@ ne_session.@NEON_OBJEXT@\t\\\n\tne_basic.@NEON_OBJEXT@ ne_string.@NEON_OBJEXT@\t\t\t\\\n\tne_uri.@NEON_OBJEXT@ ne_dates.@NEON_OBJEXT@\t\t\t\\\n\tne_alloc.@NEON_OBJEXT@ ne_md5.@NEON_OBJEXT@\t\t\t\\\n\tne_utils.@NEON_OBJEXT@ ne_socket.@NEON_OBJEXT@\t\t\t\\\n\tne_auth.@NEON_OBJEXT@ ne_redirect.@NEON_OBJEXT@\t\t\t\\\n\tne_compress.@NEON_OBJEXT@ ne_i18n.@NEON_OBJEXT@\t\t\t\\\n\tne_pkcs11.@NEON_OBJEXT@ ne_socks.@NEON_OBJEXT@\t\t\t\\\n\tne_ssl.@NEON_OBJEXT@\n\nNEON_DAVOBJS = $(NEON_BASEOBJS) \\\n\tne_207.@NEON_OBJEXT@ ne_xml.@NEON_OBJEXT@ \\\n\tne_props.@NEON_OBJEXT@ ne_locks.@NEON_OBJEXT@ \\\n\tne_xmlreq.@NEON_OBJEXT@\n\nOBJECTS = @NEONOBJS@ @NEON_EXTRAOBJS@\n\n.SUFFIXES:\n.SUFFIXES: .c .lo .o\n\n.PHONY: all all-@NEON_BUILD_BUNDLED@ check-c++ check-incl update-tables \\\n\tupdate-deps\n\nNEON_TARGET = @NEON_TARGET@\n\n# Thanks to gettext for this neat trick.\nall: all-@NEON_BUILD_BUNDLED@\n\nall-yes: $(NEON_TARGET)\nall-no:\n\t@echo \"Bundled neon build not being used.\"\n\n.c.lo:\n\t$(LT_COMPILE) -c $< -o $@\n.c.o:\n\t$(COMPILE) -c $< -o $@\n\nlibneon.la: $(OBJECTS)\n\t$(LINK) -rpath $(libdir) $(NEON_LINK_FLAGS) -o $@ $(OBJECTS) $(LIBS)\n\nlibneon.a: $(OBJECTS)\n\t@rm -f $@\n\t$(AR) cru $@ $(OBJECTS)\n\t$(RANLIB) $@\n\nclean:\n\trm -f $(NEON_TARGET) *.o *.lo *.bbg *.bb *.gc*\n\trm -rf .libs\n\nmktable: mktable.lo\n\t$(LINK) -o $@ mktable.lo\n\nc++.c: Makefile\n\tfind . -name ne_\\*.h -print | sed 's/.*/#include \"&\"/;/ne_priv/d;/ne_internal.h/d;/ne_ntlm.h/d;/ne_acl.h/d' > $@\n\techo \"int main(void) {}\" >> $@\n\ncheck-c++: c++.c\n\tc++ -I. c++.c\n\ncheck-incl:\n\t@for f in ne_*.h; do\t\t\t\t\t\t\\\n\t [ x\"$$f\" != \"xne_internal.h\" ] || continue;\t\t\t\\\n\t [ x\"$$f\" != \"xne_ntlm.h\" ] || continue;\t\t\t\\\n\t echo Checking $$f...;\t\t\t\t\t\t\\\n\t echo \"#include \\\"$$f\\\"\" > checkincl.c;\t\t\t\t\\\n\t $(LT_COMPILE) -c checkincl.c -o checkincl.o || exit 1; done\n\n# Update generated character lookup tables.\nupdate-tables: mktable\n\t@for n in `./mktable`; do\t\t\t\t\t\t\\\n\t  for f in `grep -l \"mktable $$n\" ne*.c`; do\t\t\t\t\\\n\t    new=`mktemp`;\t\t\t\t\t\t\t\\\n\t    (sed \"/.* Generated with .mktable $$n/,\\$$d\" $$f;\t\t\t\\\n\t     ./mktable $$n;\t\t\t\t\t\t\t\\\n\t     sed \"0,/.* Generated code from .mktable $$n. ends/d\" $$f) > $$new;\t\\\n\t     mv $$new $$f;\t\t\t\t\t\t\t\\\n\t  done\t\t\t\t\t\t\t\t\t\\\n\tdone\n\n# Update generated dependencies below; requires cc -MM as in gcc.\nupdate-deps:\n\tfor f in `echo $(OBJECTS) | sed 's/\\\\.@NEON_OBJEXT@/.c/g;s/ne_openssl.c//;s/ne_gnutls.c//;s/ne_pkcs11.c//;s/ne_stubssl.c//'`; do \\\n\t  $(CC) $(CPPFLAGS) -MM -c $$f; \\\n\tdone | sed 's, \\.\\./, $$(top_builddir)/,g;s, /[^ ]*.h,,g;/^  .$$/d;s/\\.o: /.@NEON''_OBJEXT@: /' > new-deps\n\tsed '/[-]--CUT---/q' Makefile.in > Makefile.new\n\tcat Makefile.new new-deps > Makefile.in\n\trm new-deps Makefile.new\n\nne_openssl.@NEON_OBJEXT@: ne_openssl.c $(top_builddir)/config.h ne_ssl.h ne_defs.h ne_string.h \\\n  ne_alloc.h ne_session.h ne_uri.h ne_socket.h ne_internal.h ne_private.h \\\n  ne_request.h ne_utils.h ne_pkcs11.h ne_privssl.h\nne_stubssl.@NEON_OBJEXT@: ne_stubssl.c $(top_builddir)/config.h ne_ssl.h ne_defs.h ne_session.h \\\n  ne_uri.h ne_socket.h\nne_pkcs11.@NEON_OBJEXT@: ne_pkcs11.c $(top_builddir)/config.h ne_pkcs11.h ne_defs.h ne_session.h \\\n  ne_ssl.h ne_uri.h ne_socket.h ne_internal.h ne_privssl.h \\\n  ne_alloc.h ne_private.h ne_request.h ne_utils.h ne_string.h\nne_gnutls.@NEON_OBJEXT@: ne_gnutls.c $(top_builddir)/config.h ne_ssl.h ne_defs.h \\\n  ne_string.h ne_alloc.h ne_session.h ne_uri.h ne_socket.h ne_internal.h \\\n  ne_private.h ne_request.h ne_utils.h ne_privssl.h\n#### ---CUT--- DO NOT REMOVE THIS LINE.  Generated dependencies follow.  ####\nne_request.@NEON_OBJEXT@: ne_request.c $(top_builddir)/config.h ne_internal.h ne_defs.h ne_alloc.h \\\n ne_request.h ne_utils.h ne_string.h ne_session.h ne_ssl.h ne_uri.h \\\n ne_socket.h ne_dates.h ne_private.h\nne_session.@NEON_OBJEXT@: ne_session.c $(top_builddir)/config.h \\\n ne_session.h ne_ssl.h ne_defs.h ne_uri.h ne_socket.h ne_alloc.h ne_utils.h \\\n ne_internal.h ne_string.h ne_dates.h ne_private.h ne_request.h\nne_basic.@NEON_OBJEXT@: ne_basic.c $(top_builddir)/config.h ne_request.h ne_utils.h ne_defs.h \\\n ne_string.h ne_alloc.h ne_session.h ne_ssl.h ne_uri.h ne_socket.h \\\n ne_basic.h ne_207.h ne_xml.h ne_locks.h ne_dates.h ne_internal.h\nne_string.@NEON_OBJEXT@: ne_string.c $(top_builddir)/config.h ne_alloc.h ne_defs.h ne_string.h \\\n ne_internal.h\nne_uri.@NEON_OBJEXT@: ne_uri.c $(top_builddir)/config.h ne_string.h ne_defs.h ne_alloc.h ne_uri.h\nne_dates.@NEON_OBJEXT@: ne_dates.c $(top_builddir)/config.h ne_alloc.h ne_defs.h ne_dates.h \\\n ne_string.h\nne_alloc.@NEON_OBJEXT@: ne_alloc.c $(top_builddir)/config.h ne_alloc.h ne_defs.h\nne_md5.@NEON_OBJEXT@: ne_md5.c $(top_builddir)/config.h ne_md5.h ne_defs.h ne_string.h ne_alloc.h\nne_utils.@NEON_OBJEXT@: ne_utils.c $(top_builddir)/config.h ne_utils.h ne_defs.h ne_string.h \\\n ne_alloc.h ne_dates.h\nne_socket.@NEON_OBJEXT@: ne_socket.c $(top_builddir)/config.h ne_privssl.h ne_ssl.h ne_defs.h \\\n ne_socket.h ne_internal.h ne_utils.h ne_string.h ne_alloc.h ne_sspi.h\nne_auth.@NEON_OBJEXT@: ne_auth.c $(top_builddir)/config.h ne_dates.h ne_defs.h ne_request.h \\\n ne_utils.h ne_string.h ne_alloc.h ne_session.h ne_ssl.h ne_uri.h \\\n ne_socket.h ne_auth.h ne_internal.h\nne_redirect.@NEON_OBJEXT@: ne_redirect.c $(top_builddir)/config.h ne_session.h ne_ssl.h ne_defs.h \\\n ne_uri.h ne_socket.h ne_request.h ne_utils.h ne_string.h ne_alloc.h \\\n ne_redirect.h ne_internal.h\nne_compress.@NEON_OBJEXT@: ne_compress.c $(top_builddir)/config.h ne_request.h ne_utils.h \\\n ne_defs.h ne_string.h ne_alloc.h ne_session.h ne_ssl.h ne_uri.h \\\n ne_socket.h ne_compress.h ne_internal.h\nne_i18n.@NEON_OBJEXT@: ne_i18n.c $(top_builddir)/config.h ne_i18n.h ne_defs.h\nne_socks.@NEON_OBJEXT@: ne_socks.c $(top_builddir)/config.h ne_internal.h ne_defs.h ne_string.h \\\n ne_alloc.h ne_socket.h ne_ssl.h ne_utils.h\nne_ssl.@NEON_OBJEXT@: ne_ssl.c $(top_builddir)/config.h ne_alloc.h ne_defs.h ne_utils.h \\\n ne_internal.h ne_string.h ne_privssl.h ne_ssl.h ne_socket.h\nne_207.@NEON_OBJEXT@: ne_207.c $(top_builddir)/config.h ne_alloc.h ne_defs.h ne_utils.h ne_xml.h \\\n ne_xmlreq.h ne_request.h ne_string.h ne_session.h ne_ssl.h ne_uri.h \\\n ne_socket.h ne_207.h ne_basic.h ne_internal.h\nne_xml.@NEON_OBJEXT@: ne_xml.c $(top_builddir)/config.h ne_internal.h ne_defs.h ne_alloc.h \\\n ne_xml.h ne_utils.h ne_string.h\nne_props.@NEON_OBJEXT@: ne_props.c $(top_builddir)/config.h ne_alloc.h ne_defs.h ne_xmlreq.h \\\n ne_request.h ne_utils.h ne_string.h ne_session.h ne_ssl.h ne_uri.h \\\n ne_socket.h ne_xml.h ne_props.h ne_207.h ne_basic.h ne_locks.h \\\n ne_internal.h\nne_locks.@NEON_OBJEXT@: ne_locks.c $(top_builddir)/config.h ne_alloc.h ne_defs.h ne_request.h \\\n ne_utils.h ne_string.h ne_session.h ne_ssl.h ne_uri.h ne_socket.h \\\n ne_xml.h ne_locks.h ne_basic.h ne_props.h ne_207.h ne_internal.h \\\n ne_xmlreq.h\nne_xmlreq.@NEON_OBJEXT@: ne_xmlreq.c $(top_builddir)/config.h ne_internal.h ne_defs.h ne_xmlreq.h \\\n ne_request.h ne_utils.h ne_string.h ne_alloc.h ne_session.h ne_ssl.h \\\n ne_uri.h ne_socket.h ne_xml.h ne_basic.h\nne_oldacl.@NEON_OBJEXT@: ne_oldacl.c $(top_builddir)/config.h ne_request.h ne_utils.h ne_defs.h \\\n ne_string.h ne_alloc.h ne_session.h ne_ssl.h ne_uri.h ne_socket.h \\\n ne_locks.h ne_acl.h ne_xml.h\nne_acl3744.@NEON_OBJEXT@: ne_acl3744.c $(top_builddir)/config.h ne_request.h ne_utils.h ne_defs.h \\\n ne_string.h ne_alloc.h ne_session.h ne_ssl.h ne_uri.h ne_socket.h \\\n ne_locks.h ne_acl3744.h ne_xml.h\n"
  },
  {
    "path": "src/README",
    "content": "This is the source directory of the 'neon' HTTP/WebDAV client library,\nwhich can be bundled inside other packages. For the complete neon\npackage, see <https://notroj.github.io/neon/>\n\nThis source directory may be distributed and/or modified under the\nterms of the GNU Library General Public License, as given in\nCOPYING.LIB.\n\nPlease send questions, bug reports, feature requests, etc, regarding\nthe neon library, to the mailing list at <neon@lists.manyfish.co.uk>\n"
  },
  {
    "path": "src/memleak.h",
    "content": "/* \n   Memory leak wrappers\n   Copyright (C) 2003-2021, Joe Orton <joe@manyfish.co.uk>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n   \n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n\n/* WARNING: THIS IS AN INTERNAL NEON INTERFACE AND MUST NOT BE USED\n * from NEON APPLICATIONS. */\n\n/* This file contains an alternate interface to the memory allocation\n * wrappers in ne_alloc.c, which perform simple leak detection.  It\n * MUST NOT BE INSTALLED, or used from neon applications. */\n\n#ifndef MEMLEAK_H\n#define MEMLEAK_H\n\n#include <stdio.h>\n\n#define ne_malloc(s) ne_malloc_ml(s, __FILE__, __LINE__)\n#define ne_calloc(s) ne_calloc_ml(s, __FILE__, __LINE__)\n#define ne_realloc(p, s) ne_realloc_ml(p, s, __FILE__, __LINE__)\n#define ne_strdup(s) ne_strdup_ml(s, __FILE__, __LINE__)\n#define ne_strndup(s, n) ne_strndup_ml(s, n, __FILE__, __LINE__)\n#define ne_free ne_free_ml\n\n/* Prototypes of allocation functions: */\nvoid *ne_malloc_ml(size_t size, const char *file, int line);\nvoid *ne_calloc_ml(size_t size, const char *file, int line);\nvoid *ne_realloc_ml(void *ptr, size_t s, const char *file, int line);\nchar *ne_strdup_ml(const char *s, const char *file, int line);\nchar *ne_strndup_ml(const char *s, size_t n, const char *file, int line);\nvoid ne_free_ml(void *ptr);\n\n/* Dump the list of currently allocated blocks to 'f'. */\nvoid ne_alloc_dump(FILE *f);\n\n/* Current number of bytes in allocated but not free'd. */\nextern size_t ne_alloc_used;\n\n#endif /* MEMLEAK_H */\n"
  },
  {
    "path": "src/mktable.c",
    "content": "/* \n   Character lookup table generator\n   Copyright (C) 2022, Joe Orton <joe@manyfish.co.uk>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n   \n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n\n#include <string.h>\n#include <stdio.h>\n#include <ctype.h>\n#include <stdlib.h>\n\ntypedef unsigned char (*generator)(unsigned char ch);\n\nstatic unsigned char gen_clean(unsigned char ch)\n{\n    return isprint(ch) ? ch : 0x20;\n}\n\nstatic unsigned char gen_lower(unsigned char ch)\n{\n    return tolower(ch);\n}\n\nstatic unsigned char gen_upper(unsigned char ch)\n{\n    return toupper(ch);\n}\n\nstatic unsigned char gen_quote(unsigned char ch)\n{\n    return !isascii(ch) || !isprint(ch) ? 4 : 1;\n}\n\n/* VALID_B64: fail if 'ch' is not a valid base64 character */\n#define VALID_B64(ch) (((ch) >= 'A' && (ch) <= 'Z') || \\\n                       ((ch) >= 'a' && (ch) <= 'z') || \\\n                       ((ch) >= '0' && (ch) <= '9') || \\\n                       (ch) == '/' || (ch) == '+' || (ch) == '=')\n\n/* DECODE_B64: decodes a valid base64 character. */\n#define DECODE_B64(ch) ((ch) >= 'a' ? ((ch) + 26 - 'a') : \\\n                        ((ch) >= 'A' ? ((ch) - 'A') : \\\n                         ((ch) >= '0' ? ((ch) + 52 - '0') : \\\n                          ((ch) == '+' ? 62 : 63))))\n\nstatic unsigned char valid_b64(unsigned char ch)\n{\n    return VALID_B64(ch) ? 1 : 0;\n}\n\nstatic unsigned char decode_b64(unsigned char ch)\n{\n    return DECODE_B64(ch);\n}\n\n/* Username safety lookup table; \"SF\" for characters which are safe to\n * include in 2617-style username parameter values, else \"NS\" for\n * non-safe characters.  Determined from RFC7230§3.2.6 - everything in\n * qdtext EXCEPT obs-text (which is \"non-ASCII\") is treated as safe to\n * include in a quoted username:\n      qdtext         = HTAB / SP /%x21 / %x23-5B / %x5D-7E / obs-text\n     obs-text       = %x80-FF\n*/\nstatic unsigned char safe_username(unsigned char ch)\n{\n    return (ch == '\\t' || ch == ' ' || ch == 0x21\n            || (ch >= 0x23 && ch <= 0x7E && ch != 0x5C))\n            ? 0 : 1;\n}\n\n#define QT 3\n#define NQ 1\n\nstatic unsigned char gen_extparam(unsigned char ch)\n{\n    switch (ch) {\n    case '!': case '#': case '$': case '&': case '+': case '-': case '.':\n    case '^': case '_': case '`': case '|': case '~':\n        return NQ;\n    default:\n        return isalnum(ch) ? NQ : QT;\n    }\n}\n\n/*\n * Map: '0'-'9' => 0-9\n * reason-phrase characters => 0-10\n * bad things => 99\n *  \n * RFC 9112: reason-phrase  = 1*( HTAB / SP / VCHAR / obs-text )\n * RFC 5234: VCHAR          = %x21-7E\n * RFC 9110: obs-text       = %x80-FF\n */\nstatic unsigned char gen_status_line(unsigned char ch)\n{\n    if (ch >= '0' && ch <= '9')\n        return ch - '0';\n\n    if (ch == '\\t' || ch == ' ' \n        || (ch >= 0x21 && ch != 0x7F)) {\n        return 10;\n    }\n\n    return 99;\n}\n\n/* https://www.rfc-editor.org/rfc/rfc9110#name-tokens\n token          = 1*tchar\n\n tchar          = \"!\" / \"#\" / \"$\" / \"%\" / \"&\" / \"'\" / \"*\"\n                   / \"+\" / \"-\" / \".\" / \"^\" / \"_\" / \"`\" / \"|\" / \"~\"\n                   / DIGIT / ALPHA\n                   ; any VCHAR, except delimiters\n\n VCHAR          =  %x21-7E\n delimiters = (DQUOTE and \"(),/:;<=>?@[\\]{}\")\n*/\n\nstatic unsigned char gen_token(unsigned char ch)\n{\n    switch (ch) {\n    case '!': case '#': case '$': case '%': case '&': case '\\'': case '*':\n    case '+': case '-': case '.': case '^': case '_': case '`': case '|':\n    case '~':\n        return ch;\n    case '(': case ')': case ',': case '/': case ':': case ';': case '<':\n    case '=': case '>': case '?': case '@': case '[': case '\\\\': case ']':\n    case '{': case '}': case '\"':\n        return 0;\n    default:\n        return ch >= 0x21 && ch <= 0x7E ? tolower(ch) : 0;\n    }\n}\n\n#define FLAG_DECIMAL (0x01)\n#define FLAG_SHORT   (0x02)\n\nstatic const struct {\n    const char *name;\n    generator fn;\n    unsigned flags;\n} generators[] = {\n    { \"strclean\", gen_clean, 0 },\n    { \"tolower\", gen_lower, 0 },\n    { \"toupper\", gen_upper, 0 },\n    { \"validb64\", valid_b64, FLAG_DECIMAL | FLAG_SHORT },\n    { \"decodeb64\", decode_b64, 0 },\n    { \"quote\", gen_quote, FLAG_DECIMAL | FLAG_SHORT },\n    { \"status_line\", gen_status_line, FLAG_DECIMAL | FLAG_SHORT },\n    { \"extparam\", gen_extparam, FLAG_DECIMAL | FLAG_SHORT },\n    { \"safe_username\", safe_username, FLAG_DECIMAL | FLAG_SHORT },\n    { \"http_token\", gen_token, 0 },\n};\n\nstatic void fail(const char *err, const char *arg)\n{\n    printf(\"mktable: %s (%s)\\n\", err, arg);\n    exit(1);\n}\n\nint main(int argc, const char **argv)\n{\n    generator fn = NULL;\n    unsigned n, wrap, flags = 0;\n\n    if (argc != 2) {\n        for (n = 0; n < sizeof(generators) / sizeof(generators[0]); n++) {\n            puts(generators[n].name);\n        }\n        return 0;\n    }\n\n    for (n = 0; n < sizeof(generators) / sizeof(generators[0]); n++) {\n        if (strcmp(generators[n].name, argv[1]) == 0) {\n            fn = generators[n].fn;\n            flags = generators[n].flags;\n            break;\n        }\n    }\n\n    if (fn == NULL) {\n        fail(\"Unrecognized generator name\", argv[1]);\n    }\n\n    wrap = (flags & FLAG_SHORT) ? 16 : 8;\n    \n    printf(\"/* Generated with 'mktable %s', do not alter here -- */\\n\", argv[1]);\n    printf(\"static const unsigned char table_%s[256] = {\", argv[1]);\n    for (n = 0; n < 256; n++) {\n        unsigned ch = fn(n);\n        if (n % wrap == 0)\n            printf(\"%s\\n/* x%02X */ \", n > 0 ? \",\" : \"\", n);\n        else\n            printf(\", \");\n        if (flags & FLAG_DECIMAL)\n            printf(\"%u\", ch);\n        else\n            printf(\"0x%02x\", ch);\n    }\n\n    printf(\"\\n}; /* -- Generated code from 'mktable %s' ends. */\\n\", argv[1]);\n\n    return 0;\n}\n"
  },
  {
    "path": "src/ne_207.c",
    "content": "/* \n   WebDAV 207 multi-status response handling\n   Copyright (C) 1999-2023, Joe Orton <joe@manyfish.co.uk>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n   \n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n\n/* Generic handling for WebDAV 207 Multi-Status responses. */\n\n#include \"config.h\"\n\n#ifdef HAVE_STDLIB_H\n#include <stdlib.h>\n#endif\n#include <string.h>\n\n#include \"ne_alloc.h\"\n#include \"ne_utils.h\"\n#include \"ne_xml.h\"\n#include \"ne_xmlreq.h\"\n#include \"ne_207.h\"\n#include \"ne_uri.h\"\n#include \"ne_basic.h\"\n\n#include \"ne_internal.h\"\n\nstruct ne_207_parser_s {\n    ne_207_start_response *start_response;\n    ne_207_end_response *end_response;\n    ne_207_start_propstat *start_propstat;\n    ne_207_end_propstat *end_propstat;\n    ne_xml_parser *parser;\n    void *userdata;\n    unsigned int flags;\n\n    ne_uri base;\n\n    ne_buffer *cdata;\n\n    /* remember whether we are in a response: the validation\n     * doesn't encapsulate this since we only count as being \n     * \"in a response\" when we've seen the href element. */\n    int in_response;\n\n    /* current position */\n    void *response, *propstat;\n    /* caching */\n    ne_status status;\n    char *description, *href;\n};\n\n#define ELM_multistatus 1\n#define ELM_response 2\n#define ELM_responsedescription 3\n#define ELM_href 4\n#define ELM_prop (NE_207_STATE_PROP)\n#define ELM_status 6\n#define ELM_propstat 7\n\nstatic const struct ne_xml_idmap map207[] = {\n    { \"DAV:\", \"multistatus\", ELM_multistatus },\n    { \"DAV:\", \"response\", ELM_response },\n    { \"DAV:\", \"responsedescription\", ELM_responsedescription },\n    { \"DAV:\", \"href\", ELM_href },\n    { \"DAV:\", \"propstat\", ELM_propstat },\n    { \"DAV:\", \"prop\",  ELM_prop },\n    { \"DAV:\", \"status\", ELM_status }\n};\n\n/* Set the callbacks for the parser */\nvoid ne_207_set_response_handlers(ne_207_parser *p,\n                                  ne_207_start_response *start,\n                                  ne_207_end_response *end)\n{\n    p->start_response = start;\n    p->end_response = end;\n}\n\nvoid ne_207_set_propstat_handlers(ne_207_parser *p,\n\t\t\t\t   ne_207_start_propstat *start,\n\t\t\t\t   ne_207_end_propstat *end)\n{\n    p->start_propstat = start;\n    p->end_propstat = end;\n}\n\nvoid *ne_207_get_current_response(ne_207_parser *p)\n{\n    return p->response;\n}\n\nvoid *ne_207_get_current_propstat(ne_207_parser *p)\n{\n    return p->propstat;\n}\n\n/* return non-zero if (child, parent) is an interesting element */\nstatic int can_handle(int parent, int child) \n{\n    return (parent == 0 && child == ELM_multistatus) ||\n        (parent == ELM_multistatus && child == ELM_response) ||\n        (parent == ELM_response && \n         (child == ELM_href || child == ELM_status || \n          child == ELM_propstat || child == ELM_responsedescription)) ||\n        (parent == ELM_propstat &&\n         (child == ELM_prop || child == ELM_status ||\n          child == ELM_responsedescription));\n}\n\nstatic int cdata_207(void *userdata, int state, const char *buf, size_t len)\n{\n    ne_207_parser *p = userdata;\n\n    if ((state == ELM_href\n         || state == ELM_responsedescription\n         || state == ELM_status) && p->cdata->used + len < 2048) {\n        if (p->cdata->used == 1) {\n            /* Strip leading whitespace only. */\n            while (len && strchr(\"\\r\\n\\t \", *buf) != NULL) {\n                buf++;\n                len--;\n            }\n        }\n\n        if (len) ne_buffer_append(p->cdata, buf, len);\n    }\n\n    return 0;\n}\n\nstatic int start_element(void *userdata, int parent, \n                         const char *nspace, const char *name, \n                         const char **atts) \n{\n    ne_207_parser *p = userdata;\n    int state = ne_xml_mapid(map207, NE_XML_MAPLEN(map207), nspace, name);\n\n    if (!can_handle(parent, state))\n        return NE_XML_DECLINE;\n\n    /* if not in a response, ignore everything. */\n    if (!p->in_response && state != ELM_response && state != ELM_multistatus &&\n        state != ELM_href)\n        return NE_XML_DECLINE;\n\n    if (state == ELM_propstat && p->start_propstat) {\n        p->propstat = p->start_propstat(p->userdata, p->response);\n        if (p->propstat == NULL) {\n            NE_DEBUG(NE_DBG_XML, \"[207] start-propstat callback failed, \"\n                     \"aborting parse, parser error is: %s.\\n\",\n                     ne_xml_get_error(p->parser));\n            return NE_XML_ABORT;\n        }\n    }\n\n    ne_buffer_clear(p->cdata);\n\n    return state;\n}\n\n#define GIVE_STATUS(p) ((p)->status.reason_phrase?&(p)->status:NULL)\n\n#define HAVE_CDATA(p) ((p)->cdata->used > 1)\n\nstatic int \nend_element(void *userdata, int state, const char *nspace, const char *name)\n{\n    ne_207_parser *p = userdata;\n    char *cdata = p->cdata->data;\n\n    switch (state) {\n    case ELM_responsedescription:\n\tif (HAVE_CDATA(p)) {\n            if (p->description) ne_free(p->description);\n\t    p->description = ne_strclean(ne_strdup(cdata));\n\t}\n\tbreak;\n    case ELM_href:\n\t/* Now we have the href, begin the response */\n\tif (p->start_response && HAVE_CDATA(p)) {\n            ne_uri ref, resolved;\n            int ret;\n            char *hh = NULL;\n\n            /* Trim any trailing whitespace. */\n            cdata = ne_shave(cdata, \"\\r\\n\\t \");\n\n            if (p->flags & NE_207_MSSP_ESCAPING) {\n                hh = ne_path_escapef(cdata, NE_PATH_NONURI);\n                NE_DEBUG(NE_DBG_XML, \"207: Enabled href escaping hacks [%s]->[%s]\\n\",\n                         cdata, hh);\n                cdata = hh;\n            }\n\n            ret = ne_uri_parse(cdata, &ref);\n            if (!ret) {\n                ne_uri_resolve(&p->base, &ref, &resolved);\n\n                p->response = p->start_response(p->userdata, &resolved);\n                p->in_response = 1;\n                ne_uri_free(&resolved);\n            }\n            else {\n                NE_DEBUG(NE_DBG_XML, \"207: Failed to parse href: [%s]\\n\", cdata);\n            }\n            ne_uri_free(&ref);\n            if (hh) ne_free(hh);\n\t}\n\tbreak;\n    case ELM_status:\n\tif (HAVE_CDATA(p)) {\n            if (p->status.reason_phrase) ne_free(p->status.reason_phrase);\n\t    if (ne_parse_statusline(cdata, &p->status)) {\n\t\tchar buf[500];\n                NE_DEBUG(NE_DBG_HTTP, \"[207] Invalid status-line: [%s]\\n\", cdata);\n\t\tne_snprintf(buf, 500, \n\t\t\t    _(\"Invalid HTTP status line in status element \"\n                              \"at line %d of response:\\nStatus line was: %s\"),\n\t\t\t    ne_xml_currentline(p->parser), cdata);\n\t\tne_xml_set_error(p->parser, buf);\n\t\treturn -1;\n\t    }\n            else {\n                /* Shave trailing spaces from the reason-phrase; any\n                 * other trailing whitespace will have been\n                 * strclean()ed into spaces. */\n                ne_shave(p->status.reason_phrase, \" \");\n                NE_DEBUG(NE_DBG_XML, \"[207] valid status-line: %s\\n\", cdata);\n\t    }\n\t}\n\tbreak;\n    case ELM_propstat:\n\tif (p->end_propstat)\n\t    p->end_propstat(p->userdata, p->propstat, GIVE_STATUS(p),\n\t\t\t    p->description);\n\tp->propstat = NULL;\n        if (p->description) ne_free(p->description);\n        if (p->status.reason_phrase) ne_free(p->status.reason_phrase);\n        p->description = p->status.reason_phrase = NULL;\n\tbreak;\n    case ELM_response:\n        if (!p->in_response) break;\n\tif (p->end_response)\n\t    p->end_response(p->userdata, p->response, GIVE_STATUS(p),\n\t\t\t    p->description);\n\tp->response = NULL;\n\tp->in_response = 0;\n        if (p->description) ne_free(p->description);\n        if (p->status.reason_phrase) ne_free(p->status.reason_phrase);\n        p->description = p->status.reason_phrase = NULL;\n\tbreak;\n    }\n    return 0;\n}\n\nne_207_parser *ne_207_create(ne_xml_parser *parser, const ne_uri *base, \n                             void *userdata)\n{\n    ne_207_parser *p = ne_calloc(sizeof *p);\n\n    p->parser = parser;\n    p->userdata = userdata;\n    p->cdata = ne_buffer_create();\n\n    ne_uri_copy(&p->base, base);\n\n    /* Add handler for the standard 207 elements */\n    ne_xml_push_handler(parser, start_element, cdata_207, end_element, p);\n    \n    return p;\n}\n\nvoid ne_207_set_flags(ne_207_parser *p, unsigned int flags)\n{\n    p->flags = flags;\n}\n\nvoid ne_207_destroy(ne_207_parser *p) \n{\n    if (p->status.reason_phrase) ne_free(p->status.reason_phrase);\n    ne_buffer_destroy(p->cdata);\n    ne_uri_free(&p->base);\n    ne_free(p);\n}\n\nint ne_accept_207(void *userdata, ne_request *req, const ne_status *status)\n{\n    return (status->code == 207);\n}\n\n/* Handling of 207 errors: we keep a string buffer, and append\n * messages to it as they come down.\n *\n * Note, 424 means it would have worked but something else went wrong.\n * We will have had the error for \"something else\", so we display\n * that, and skip 424 errors. */\n\n/* This is passed as userdata to the 207 code. */\nstruct context {\n    char *path;\n    ne_buffer *buf;\n    unsigned int is_error;\n};\n\nstatic void *start_response(void *userdata, const ne_uri *uri)\n{\n    struct context *ctx = userdata;\n\n    /* Assume the only part of the URI that matters is the path, but\n     * could compare it to be sure. */\n    if (ctx->path) ne_free(ctx->path);\n    ctx->path = ne_strdup(uri->path);\n    return NULL;\n}\n\nstatic void handle_error(struct context *ctx, const ne_status *status,\n\t\t\t const char *description)\n{\n    if (status && status->klass != 2 && status->code != 424) {\n        if (ctx->is_error)\n            ne_buffer_czappend(ctx->buf, \", \");\n\tctx->is_error = 1;\n\tne_buffer_snprintf(ctx->buf, 512, \"%s: %d %s\",\n                           ctx->path, status->code, status->reason_phrase);\n\tif (description) {\n\t    ne_buffer_concat(ctx->buf, \" (\", description, \")\", NULL);\n\t}\n    }\n\n}\n\nstatic void end_response(void *userdata, void *response,\n\t\t\t const ne_status *status, const char *description)\n{\n    struct context *ctx = userdata;\n    handle_error(ctx, status, description);\n}\n\nstatic void \nend_propstat(void *userdata, void *propstat,\n\t     const ne_status *status, const char *description)\n{\n    struct context *ctx = userdata;\n    handle_error(ctx, status, description);\n}\n\n/* Dispatch a DAV request and handle a 207 error response appropriately */\nint ne_simple_request(ne_session *sess, ne_request *req)\n{\n    int ret;\n    struct context ctx = {0};\n    ne_207_parser *p207;\n    ne_xml_parser *p = ne_xml_create();\n    ne_uri base = {0};\n\n    /* Mock up a base URI; it should really be retrieved from the\n     * request object. */\n    ne_fill_server_uri(sess, &base);\n    base.path = ne_strdup(\"/\");\n    p207 = ne_207_create(p, &base, &ctx);\n    ne_uri_free(&base);    \n\n    /* The error string is progressively written into the\n     * ne_buffer by the element callbacks */\n    ctx.buf = ne_buffer_create();\n\n    ne_207_set_response_handlers(p207, start_response, end_response);\n    ne_207_set_propstat_handlers(p207, NULL, end_propstat);\n\n    /* Parse XML responses for 207 only. */\n    ret = ne_xml_dispatchif_request(req, p, ne_accept_207, NULL);\n    if (ret == NE_OK) {\n        if (ctx.is_error) {\n            /* Catch any error parsed in the 207 case here. */\n            ne_set_error(sess, \"%s\", ctx.buf->data);\n            ret = NE_ERROR;\n            NE_DEBUG(NE_DBG_XML, \"207: Returning error %s\\n\", ctx.buf->data);\n        }\n        else if (ne_get_status(req)->klass != 2) {\n            ret = NE_ERROR;\n        }\n    }\n\n    ne_207_destroy(p207);\n    ne_xml_destroy(p);\n    ne_buffer_destroy(ctx.buf);\n    if (ctx.path) ne_free(ctx.path);\n\n    ne_request_destroy(req);\n\n    return ret;\n}\n    \n"
  },
  {
    "path": "src/ne_207.h",
    "content": "/* \n   WebDAV 207 multi-status response handling\n   Copyright (C) 1999-2021, Joe Orton <joe@manyfish.co.uk>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n   \n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n\n#ifndef NE_207_H\n#define NE_207_H\n\n#include \"ne_xml.h\"\n#include \"ne_request.h\" /* for ne_request */\n#include \"ne_uri.h\" /* for ne_uri */\n\nNE_BEGIN_DECLS\n\n/* The defined state integer for the '{DAV:}prop' element. */\n#define NE_207_STATE_PROP (50)\n/* This interface reserves the state integers 'x' where 0 < x < 100 */\n#define NE_207_STATE_TOP (100)\n\n/* Handling of 207 multistatus XML documents.  A \"multistatus\"\n * document is made up of a set of responses, each concerned with a\n * particular resource.  Each response may have an associated result\n * status and failure description.  A response is made up of a set of\n * propstats, each of which again may have an associated result status\n * and failure description. */\n\n/* Start and end response callbacks trigger at the start and end of\n * each \"response\" within the multistatus body. 'uri' gives the URI\n * of the resource which is subject of this response.  The return\n * value of a 'start_response' callback is passed as the 'response'\n * parameter to the corresponding 'end_response' parameter. */\ntypedef void *ne_207_start_response(void *userdata, const ne_uri *uri);\ntypedef void ne_207_end_response(void *userdata, void *response,\n                                 const ne_status *status,\n                                 const char *description);\n\n/* Similarly, start and end callbacks for each propstat within the\n * response.  The return value of the 'start_response' callback for\n * the response in which this propstat is contains is passed as the\n * 'response' parameter.  The return value of each 'start_propstat' is\n * passed as the 'propstat' parameter' to the corresponding\n * 'end_propstat' callback.  If the start_propstat callback returns\n * NULL, parsing is aborted (the XML parser error must be set by the\n * callback). */\ntypedef void *ne_207_start_propstat(void *userdata, void *response);\ntypedef void ne_207_end_propstat(void *userdata, void *propstat,\n                                 const ne_status *status,\n                                 const char *description);\n\ntypedef struct ne_207_parser_s ne_207_parser;\n\n/* Create 207 parser, adding handlers to the given XML parser's\n * handler stack. URI references in the 207 response will be resolved\n * relative to the base URI 'base'. */\nne_207_parser *ne_207_create(ne_xml_parser *parser, const ne_uri *base, \n                             void *userdata);\n\n/* Enable special href escaping hacks for Microsoft SharePoint. */\n#define NE_207_MSSP_ESCAPING (0x0001)\n\n/* Set given flags for the parser. */\nvoid ne_207_set_flags(ne_207_parser *p, unsigned int flags);\n\n/* Register response handling callbacks. */\nvoid ne_207_set_response_handlers(ne_207_parser *p,\n                                  ne_207_start_response *start,\n                                  ne_207_end_response *end);\n\n/* Register propstat handling callbacks. */\nvoid ne_207_set_propstat_handlers(ne_207_parser *p, \n                                  ne_207_start_propstat *start,\n                                  ne_207_end_propstat *end);\n\n/* Destroy the parser */\nvoid ne_207_destroy(ne_207_parser *p);\n\n/* An acceptance function which only accepts 207 responses */\nint ne_accept_207(void *userdata, ne_request *req, const ne_status *status);\n\nvoid *ne_207_get_current_propstat(ne_207_parser *p);\nvoid *ne_207_get_current_response(ne_207_parser *p);\n\n/* Dispatch request 'req', returning:\n *  NE_ERROR: for a dispatch error, or a non-2xx response, or a\n *            207 response which contained a non-2xx propstat\n *  NE_OK: for a 2xx response or a 207 response which contained\n *            only 2xx-class propstats.\n * The request object is destroyed in both cases. */\nint ne_simple_request(ne_session *sess, ne_request *req);\n\nNE_END_DECLS\n\n#endif /* NE_207_H */\n"
  },
  {
    "path": "src/ne_acl.h",
    "content": "/*\n   Access control\n   Copyright (C) 2001-2021, Joe Orton <joe@manyfish.co.uk>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n\n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n\n/*\n * DEPRECATED ACL Interface.  See ne_acl3744.h for replacement API.\n */\n\n#ifndef NE_ACL_H\n#define NE_ACL_H\n\n#include \"ne_session.h\"\n\nNE_BEGIN_DECLS\n\ntypedef struct\n{\n    enum {\n\tne_acl_href,\n\tne_acl_property,\n\tne_acl_all\n    } apply;\n    \n    enum {\n\tne_acl_grant,\n\tne_acl_deny\n    } type;\n\n    char *principal;\n    int read;\n    int read_acl;\n    int write;\n    int write_acl;\n    int read_cuprivset;\n} ne_acl_entry;\n\n/* Set the ACL for the given resource to the list of ACL entries. */\nint ne_acl_set(ne_session *sess, const char *uri,\n\t       const ne_acl_entry entries[], int numentries);\n\nNE_END_DECLS\n\n#endif /* NE_ACL_H */\n"
  },
  {
    "path": "src/ne_acl3744.c",
    "content": "/*\n   Access control\n   Copyright (C) 2001-2021, Joe Orton <joe@manyfish.co.uk>\n   Copyright (C) 2001, Arun Garg <arung@pspl.co.in>\n   Copyright (C) 2007 Henrik Holst <henrik.holst2@gmail.com>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n\n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n\n/* Contributed by Arun Garg <arung@pspl.co.in> */\n\n#include \"config.h\"\n\n#include <sys/types.h>\n\n#ifdef HAVE_STRING_H\n#include <string.h>\n#endif\n#ifdef HAVE_UNISTD_H\n#include <unistd.h>\n#endif\n#ifdef HAVE_STDLIB_H\n#include <stdlib.h>\n#endif\n\n#include \"ne_request.h\"\n#include \"ne_locks.h\"\n#include \"ne_alloc.h\"\n#include \"ne_string.h\"\n#include \"ne_acl3744.h\"\n#include \"ne_uri.h\"\n#include \"ne_xml.h\" /* for NE_XML_MEDIA_TYPE */\n\n#define EOL \"\\r\\n\"\n\nstatic ne_buffer *acl_body(const ne_acl_entry *right, int count)\n{\n    ne_buffer *body = ne_buffer_create();\n    int m;\n\n    ne_buffer_zappend(body,\n\t\t      \"<?xml version=\\\"1.0\\\" encoding=\\\"utf-8\\\"?>\" EOL\n\t\t      \"<acl xmlns='DAV:'>\" EOL);\n\n    for (m = 0; m < count; m++) {\n\tconst char *type;\n\n\ttype = (right[m].type == ne_acl_grant ? \"grant\" : \"deny\");\n\n\tne_buffer_concat(body, \"<ace>\" EOL \"<principal>\", NULL);\n\n\tswitch (right[m].target) {\n\tcase ne_acl_all:\n\t    ne_buffer_czappend(body, \"<all/>\" EOL);\n\t    break;\n\tcase ne_acl_authenticated:\n\t    ne_buffer_czappend(body, \"<authenticated/>\" EOL);\n\t    break;\n\tcase ne_acl_unauthenticated:\n\t    ne_buffer_czappend(body, \"<unauthenticated/>\" EOL);\n\t    break;\n\tcase ne_acl_self:\n\t    ne_buffer_czappend(body, \"<self/>\" EOL);\n\t    break;\n\tcase ne_acl_property:\n\t    ne_buffer_concat(body, \"<property><\", right[m].tname,\n\t\t\t     \"/></property>\" EOL, NULL);\n\t    break;\n\tcase ne_acl_href:\n\t    ne_buffer_concat(body, \"<href>\", right[m].tname,\n\t\t\t     \"</href>\" EOL, NULL);\n\t    break;\n\t}\n\n\tne_buffer_concat(body, \"</principal>\" EOL \n                         \"<\", type, \">\" EOL, NULL);\n\n\tif ((right[m].privileges & NE_ACL_READ) == NE_ACL_READ)\n\t    ne_buffer_concat(body,\n\t\t\t     \"<privilege>\" \"<read/>\" \"</privilege>\" EOL,\n\t\t\t     NULL);\n\n\tif ((right[m].privileges & NE_ACL_WRITE) == NE_ACL_WRITE)\n\t    ne_buffer_concat(body,\n\t\t\t     \"<privilege>\" \"<write/>\" \"</privilege>\" EOL,\n\t\t\t     NULL);\n\n\tif ((right[m].privileges & NE_ACL_WRITE_PROPERTIES) == NE_ACL_WRITE_PROPERTIES)\n\t    ne_buffer_concat(body,\n\t\t\t     \"<privilege>\" \"<write-properties/>\" \"</privilege>\" EOL,\n\t\t\t     NULL);\n\n\tif ((right[m].privileges & NE_ACL_WRITE_CONTENT) == NE_ACL_WRITE_CONTENT)\n\t    ne_buffer_concat(body,\n\t\t\t     \"<privilege>\" \"<write-content/>\" \"</privilege>\" EOL,\n\t\t\t     NULL);\n\n\tif ((right[m].privileges & NE_ACL_UNLOCK) == NE_ACL_UNLOCK)\n\t    ne_buffer_concat(body,\n\t\t\t     \"<privilege>\" \"<unlock/>\" \"</privilege>\" EOL,\n\t\t\t     NULL);\n\n\tif ((right[m].privileges & NE_ACL_READ_ACL) == NE_ACL_READ_ACL)\n\t    ne_buffer_concat(body,\n\t\t\t     \"<privilege>\" \"<read-acl/>\" \"</privilege>\" EOL,\n\t\t\t     NULL);\n\n\tif ((right[m].privileges & NE_ACL_READ_CUPRIVSET) == NE_ACL_READ_CUPRIVSET)\n\t    ne_buffer_concat(body,\n\t\t\t     \"<privilege>\" \"<read-current-user-privileges-set/>\" \"</privilege>\" EOL,\n\t\t\t     NULL);\n\n\tif ((right[m].privileges & NE_ACL_WRITE_ACL) == NE_ACL_WRITE_ACL)\n\t    ne_buffer_concat(body,\n\t\t\t     \"<privilege>\" \"<write-acl/>\" \"</privilege>\" EOL,\n\t\t\t     NULL);\n\n\tif ((right[m].privileges & NE_ACL_BIND) == NE_ACL_BIND)\n\t    ne_buffer_concat(body,\n\t\t\t     \"<privilege>\" \"<bind/>\" \"</privilege>\" EOL,\n\t\t\t     NULL);\n\n\tif ((right[m].privileges & NE_ACL_UNBIND) == NE_ACL_UNBIND)\n\t    ne_buffer_concat(body,\n\t\t\t     \"<privilege>\" \"<unbind/>\" \"</privilege>\" EOL,\n\t\t\t     NULL);\n\n\tif ((right[m].privileges & NE_ACL_ALL) == NE_ACL_ALL)\n\t    ne_buffer_concat(body,\n\t\t\t     \"<privilege>\" \"<all/>\" \"</privilege>\" EOL,\n\t\t\t     NULL);\n\n\tne_buffer_concat(body, \"</\", type, \">\" EOL, NULL);\n\tne_buffer_czappend(body, \"</ace>\" EOL);\n    }\n\n    ne_buffer_czappend(body, \"</acl>\" EOL);\n\n    return body;\n}\n\nint ne_acl3744_set(ne_session *sess, const char *uri,\n                   const ne_acl_entry *entries, int numentries)\n{\n    int ret;\n    ne_request *req = ne_request_create(sess, \"ACL\", uri);\n    ne_buffer *body = acl_body(entries, numentries);\n\n#ifdef NE_HAVE_DAV\n    ne_lock_using_resource(req, uri, 0);\n#endif\n\n    ne_set_request_body_buffer(req, body->data, ne_buffer_size(body));\n    ne_add_request_header(req, \"Content-Type\", NE_XML_MEDIA_TYPE);\n    ret = ne_request_dispatch(req);\n\n    ne_buffer_destroy(body);\n\n    if (ret == NE_OK && ne_get_status(req)->code == 207) {\n\tret = NE_ERROR;\n    }\n\n    ne_request_destroy(req);\n    return ret;\n}\n"
  },
  {
    "path": "src/ne_acl3744.h",
    "content": "/*\n   Access control\n   Copyright (C) 2001-2021, Joe Orton <joe@manyfish.co.uk>\n   Copyright (C) 2001, Arun Garg <arung@pspl.co.in>\n   Copyright (C) 2007 Henrik Holst <henrik.holst2@gmail.com>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n\n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n\n#ifndef NE_ACL3744_H\n#define NE_ACL3744_H\n\n#include \"ne_session.h\"\n\nNE_BEGIN_DECLS\n\n#define NE_ACL_READ             (0x0001)\n#define NE_ACL_WRITE            (0x0002)\n#define NE_ACL_WRITE_PROPERTIES (0x0004)\n#define NE_ACL_WRITE_CONTENT    (0x0008)\n#define NE_ACL_UNLOCK           (0x0010)\n#define NE_ACL_READ_ACL         (0x0020)\n#define NE_ACL_READ_CUPRIVSET   (0x0040)\n#define NE_ACL_WRITE_ACL        (0x0080)\n#define NE_ACL_BIND             (0x0100)\n#define NE_ACL_UNBIND           (0x0200)\n#define NE_ACL_ALL              (0x0400)\n\nenum ne_acl_target {\n    ne_acl_href,\n    ne_acl_property,\n    ne_acl_all,\n    ne_acl_authenticated,\n    ne_acl_unauthenticated,\n    ne_acl_self\n};\n\nenum ne_acl_optype {\n    ne_acl_grant,\n    ne_acl_deny\n};\n\n/* A simplified representation of an Access Control Element (ACE): */\ntypedef struct {\n    /* Identify the principal(s) to which this ACE applies: */\n    enum ne_acl_target target;\n\n    /* Whether to grant or deny access: */\n    enum ne_acl_optype type;\n\n    /* If target == ne_acl_href, tname must be non-NULL and give the\n     * principal URL.  If target == ne_acl_property, tname must be\n     * non-NULL and be a property name, including an XML namespace\n     * definition, if appropriate (the default namespace being\n     * \"DAV:\").  This restricts access as described at:\n     * http://tools.ietf.org/html/rfc3744#section-5.5.1 */\n    char *tname;\n\n    /* The set of privileges to be restricted; a bit mask of one or\n     * more of the NE_ACL_* constants defined above: */\n    unsigned int privileges;\n\n} ne_acl_entry;\n\n/* Set the ACL for the given resource to the list of ACL entries. */\nint ne_acl3744_set(ne_session *sess, const char *path,\n                   const ne_acl_entry entries[], int numentries);\n\nNE_END_DECLS\n\n#endif /* NE_ACL3744_H */\n"
  },
  {
    "path": "src/ne_alloc.c",
    "content": "/* \n   Replacement memory allocation handling etc.\n   Copyright (C) 1999-2021, Joe Orton <joe@manyfish.co.uk>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n   \n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n\n#include \"config.h\"\n\n#ifdef HAVE_STRING_H\n#include <string.h>\n#endif\n\n#ifdef HAVE_STDLIB_H\n#include <stdlib.h>\n#endif\n\n#include <stdio.h>\n\n#include \"ne_alloc.h\"\n\nstatic ne_oom_callback_fn oom;\n\nvoid ne_oom_callback(ne_oom_callback_fn callback)\n{\n    oom = callback;\n}\n\n#ifndef NEON_MEMLEAK\n\n#define DO_MALLOC(ptr, len) do {\t\t\\\n    ptr = malloc((len));\t\t\t\\\n    if (!ptr) {\t\t\t\t\t\\\n\tif (oom != NULL)\t\t\t\\\n\t    oom();\t\t\t\t\\\n\tabort();\t\t\t\t\\\n    }\t\t\t\t\t\t\\\n} while(0);\n\nvoid *ne_malloc(size_t len) \n{\n    void *ptr;\n    DO_MALLOC(ptr, len);\n    return ptr;\n}\n\nvoid *ne_calloc(size_t len) \n{\n    void *ptr;\n    DO_MALLOC(ptr, len);\n    return memset(ptr, 0, len);\n}\n\nvoid *ne_realloc(void *ptr, size_t len)\n{\n    void *ret = realloc(ptr, len);\n    if (!ret) {\n\tif (oom)\n\t    oom();\n\tabort();\n    }\n    return ret;\n}\n\n#ifdef WIN32\n/* Implemented only to ensure free is bound to the correct DLL. */\nvoid ne_free(void *ptr)\n{\n    free(ptr);\n}\n#endif\n\nchar *ne_strdup(const char *s) \n{\n    char *ret;\n    DO_MALLOC(ret, strlen(s) + 1);\n    return strcpy(ret, s);\n}\n\nchar *ne_strndup(const char *s, size_t n)\n{\n    char *new;\n    DO_MALLOC(new, n+1);\n    new[n] = '\\0';\n    memcpy(new, s, n);\n    return new;\n}\n\n#else /* NEON_MEMLEAK */\n\n#include <assert.h>\n\n/* Memory-leak detection implementation: ne_malloc and friends are\n * #defined to ne_malloc_ml etc by memleak.h, which is conditionally\n * included by config.h. */\n\n/* memory allocated be ne_*alloc, but not freed. */\nsize_t ne_alloc_used = 0;\n\nstatic struct block {\n    void *ptr;\n    size_t len;\n    const char *file;\n    int line;\n    struct block *next;\n} *blocks = NULL;\n\nvoid ne_alloc_dump(FILE *f)\n{\n    struct block *b;\n\n    for (b = blocks; b != NULL; b = b->next)\n        fprintf(f, \"%\" NE_FMT_SIZE_T \"b@%s:%d%s\", b->len, b->file, b->line,\n                b->next?\", \":\"\");\n}\n\nstatic void *tracking_malloc(size_t len, const char *file, int line)\n{\n    void *ptr = malloc((len));\n    struct block *block;\n\n    if (!ptr) {\n\tif (oom) oom();\n\tabort();\n    }\n    \n    block = malloc(sizeof *block);\n    if (block != NULL) {\n        block->ptr = ptr;\n        block->len = len;\n        block->file = file;\n        block->line = line;\n        block->next = blocks;\n        blocks = block;\n        ne_alloc_used += len;\n    }\n\n    return ptr;\n}\n\nvoid *ne_malloc_ml(size_t size, const char *file, int line)\n{\n    return tracking_malloc(size, file, line);\n}\n\nvoid *ne_calloc_ml(size_t size, const char *file, int line)\n{\n    return memset(tracking_malloc(size, file, line), 0, size);\n}\n\nvoid *ne_realloc_ml(void *ptr, size_t s, const char *file, int line)\n{\n    void *ret;\n    struct block *b;\n\n    if (ptr == NULL)\n        return tracking_malloc(s, file, line);\n\n    ret = realloc(ptr, s);\n    if (!ret) {\n        if (oom) oom();\n        abort();\n    }\n    \n    for (b = blocks; b != NULL; b = b->next) {\n        if (b->ptr == ptr) {\n            ne_alloc_used += s - b->len;\n            b->ptr = ret;\n            b->len = s;\n            break;\n        }\n    }\n    assert(b != NULL);\n\n    return ret;\n}\n\nchar *ne_strdup_ml(const char *s, const char *file, int line)\n{\n    return strcpy(tracking_malloc(strlen(s) + 1, file, line), s);\n}\n\nchar *ne_strndup_ml(const char *s, size_t n, const char *file, int line)\n{\n    char *ret = tracking_malloc(n + 1, file, line);\n    ret[n] = '\\0';\n    return memcpy(ret, s, n);\n}\n\nvoid ne_free_ml(void *ptr)\n{\n    struct block *b, *last = NULL;\n\n    for (b = blocks; b != NULL; last = b, b = b->next) {\n        if (b->ptr == ptr) {\n            ne_alloc_used -= b->len;\n            if (last) \n                last->next = b->next;\n            else\n                blocks = b->next;\n            free(b);\n            break;\n        }\n    }\n\n    free(ptr);\n}\n\n#endif /* NEON_MEMLEAK */\n"
  },
  {
    "path": "src/ne_alloc.h",
    "content": "/* \n   Replacement memory allocation handling etc.\n   Copyright (C) 1999-2021, Joe Orton <joe@manyfish.co.uk>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n   \n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n\n#ifndef NE_ALLOC_H\n#define NE_ALLOC_H\n\n#include <stdlib.h>\n\n#ifndef WIN32\n#include <sys/types.h>\n#endif\n\n#include \"ne_defs.h\"\n\nNE_BEGIN_DECLS\n\ntypedef void (*ne_oom_callback_fn)(void);\n\n/* Set callback which is called if malloc() returns NULL. */\nvoid ne_oom_callback(ne_oom_callback_fn callback);\n\n#ifndef NEON_MEMLEAK\n/* Replacements for standard C library memory allocation functions,\n * which never return NULL. If the C library malloc() returns NULL,\n * neon will abort(); calling an OOM callback beforehand if one is\n * registered.  The C library will only ever return NULL if the\n * operating system does not use optimistic memory allocation. */\nvoid *ne_malloc(size_t size) ne_attribute_alloc_size(1) ne_attribute_malloc;\nvoid *ne_calloc(size_t size) ne_attribute_alloc_size(1) ne_attribute_malloc;\nvoid *ne_realloc(void *ptr, size_t s) ne_attribute_alloc_size(2);\nchar *ne_strdup(const char *s) ne_attribute_malloc;\nchar *ne_strndup(const char *s, size_t n) ne_attribute_malloc;\n#ifdef WIN32\nvoid ne_free(void *ptr);\n#else\n#define ne_free free\n#endif\n#endif\n\nNE_END_DECLS\n\n#endif /* NE_ALLOC_H */\n"
  },
  {
    "path": "src/ne_auth.c",
    "content": "/* \n   HTTP Authentication routines\n   Copyright (C) 1999-2024, Joe Orton <joe@manyfish.co.uk>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n   \n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n\n#include \"config.h\"\n\n#include <sys/types.h>\n\n#ifdef HAVE_STDLIB_H\n#include <stdlib.h>\n#endif\n#ifdef HAVE_STRING_H\n#include <string.h>\n#endif\n#ifdef HAVE_STRINGS_H\n#include <strings.h>\n#endif\n\n#include <errno.h>\n#include <time.h>\n\n#include \"ne_dates.h\"\n#include \"ne_request.h\"\n#include \"ne_auth.h\"\n#include \"ne_string.h\"\n#include \"ne_utils.h\"\n#include \"ne_alloc.h\"\n#include \"ne_uri.h\"\n#include \"ne_internal.h\"\n\n#ifdef HAVE_GSSAPI\n#ifdef HAVE_GSSAPI_GSSAPI_H\n#include <gssapi/gssapi.h>\n#ifdef HAVE_GSSAPI_GSSAPI_GENERIC_H\n#include <gssapi/gssapi_generic.h>\n#endif\n#else\n#include <gssapi.h>\n#endif\n#endif\n\n#ifdef NE_HAVE_NTLM\n#include <ntlm.h>\n#endif\n\n#ifdef HAVE_SSPI\n#include \"ne_sspi.h\"\n#endif\n \n#define HOOK_SERVER_ID \"http://webdav.org/neon/hooks/server-auth\"\n#define HOOK_PROXY_ID \"http://webdav.org/neon/hooks/proxy-auth\"\n\nstatic const struct hashalg {\n    const char *name;\n    unsigned int hash;\n    unsigned int sess; /* _session variant */\n} hashalgs[] = {\n    { \"MD5\", NE_HASH_MD5, 0 }, /* This must remain first in the array. */\n    { \"MD5-sess\", NE_HASH_MD5, 1 },\n    { \"SHA-256\", NE_HASH_SHA256, 0 },\n    { \"SHA-256-sess\", NE_HASH_SHA256, 1 },\n    { \"SHA-512-256\", NE_HASH_SHA512_256, 0 },\n    { \"SHA-512-256-sess\", NE_HASH_SHA512_256, 1 }\n};\n\n#define HASHALG_MD5 (&hashalgs[0])\n#define NUM_HASHALGS (sizeof(hashalgs)/sizeof(hashalgs[0]))\n\n/* Selected method of qop which the client is using */\ntypedef enum {\n    auth_qop_none,\n    auth_qop_auth\n} auth_qop;\n\n/* A callback/userdata pair registered by the application for\n * a particular set of protocols. */\nstruct auth_handler {\n    unsigned protomask; \n\n    ne_auth_creds old_creds;\n    ne_auth_provide new_creds;\n    void *userdata;\n    int attempt; /* number of invocations of this callback for\n                  * current request. */\n    \n    struct auth_handler *next;\n};\n\n/* A challenge */\nstruct auth_challenge {\n    const struct auth_protocol *protocol;\n    struct auth_handler *handler;\n    const char *realm, *nonce, *opaque, *domain;\n    unsigned int stale; /* if stale=true */\n    unsigned int got_qop; /* we were given a qop directive */\n    unsigned int qop_auth; /* \"auth\" token in qop attrib */\n    enum { userhash_none=0, userhash_true=1, userhash_false=2} userhash;\n    const struct hashalg *alg;\n    struct auth_challenge *next;\n};\n\nstatic const struct auth_class {\n    const char *id, *req_hdr, *resp_hdr, *resp_info_hdr;\n    int status_code; /* Response status-code to trap. */\n    int fail_code;   /* NE_* request to fail with. */\n    unsigned protomask; /* protocol mask */\n    const char *error_noauth; /* Error message template use when\n                               * giving up authentication attempts. */\n} ah_server_class = {\n    HOOK_SERVER_ID,\n    \"Authorization\", \"WWW-Authenticate\", \"Authentication-Info\",\n    401, NE_AUTH, 0,\n    N_(\"Could not authenticate to server: %s\")\n}, ah_proxy_class = {\n    HOOK_PROXY_ID,\n    \"Proxy-Authorization\", \"Proxy-Authenticate\", \"Proxy-Authentication-Info\",\n    407, NE_PROXYAUTH, NE_AUTH_PROXY,\n    N_(\"Could not authenticate to proxy server: %s\")\n};\n\n/* Internal buffer size, which must be >= NE_ABUFSIZ. */\n#define ABUFSIZE (NE_ABUFSIZ * 2)\n\n#define zero_and_free(s) do { ne__strzero(s, strlen(s)); ne_free(s); } while (0)\n\n/* Authentication session state. */\ntypedef struct {\n    ne_session *sess;\n\n    /* Which context will auth challenges be accepted? */\n    enum {\n        AUTH_ANY, /* ignore nothing. */\n        AUTH_CONNECT, /* only in response to a CONNECT request. */\n        AUTH_NOTCONNECT /* only in non-CONNECT responsees */\n    } context;\n    \n    /* Protocol type for server/proxy auth. */\n    const struct auth_class *spec;\n    \n    /* The protocol used for this authentication session */\n    const struct auth_protocol *protocol;\n\n    struct auth_handler *handlers;\n\n    /*** Session details ***/\n\n    /* The username and password we are using to authenticate with */\n    char username[ABUFSIZE];\n\n    /* This used for Basic auth */\n    char *basic; \n#ifdef HAVE_GSSAPI\n    /* for the GSSAPI/Negotiate scheme: */\n    char *gssapi_token;\n    gss_ctx_id_t gssctx;\n    gss_name_t gssname;\n    gss_OID gssmech;\n#endif\n#ifdef HAVE_SSPI\n    /* This is used for SSPI (Negotiate/NTLM) auth */\n    char *sspi_token;\n    void *sspi_context;\n    char *sspi_host;\n#endif\n#ifdef NE_HAVE_NTLM\n    enum {NTLM_INIT=0, NTLM_SENT, NTLM_DONE} ntlm_state;\n    char *ntlm_token;\n    char *ntlm_password;\n#endif\n    /* These all used for Digest auth */\n    char *realm;\n    char *nonce;\n    char *cnonce;\n    char *opaque;\n    char **domains; /* list of paths given as domain. */\n    size_t ndomains; /* size of domains array */\n    char *userhash;\n    char *username_star;\n    auth_qop qop;\n    const struct hashalg *alg;\n    unsigned int nonce_count;\n    /* The hex representation of the H(A1) value */\n    char *h_a1;\n    /* Part of the RHS of the response digest. */\n    char *response_rhs;\n} auth_session;\n\nstruct auth_request {\n    /*** Per-request details. ***/\n    ne_request *request; /* the request object. */\n\n    /* The request-target and method for the current request, */\n    const char *target;\n    const char *method;\n    \n    int attempt; /* number of times this request has been retries due\n                  * to auth challenges. */\n};\n\n/* Used if this protocol takes an unquoted non-name/value-pair\n * parameter in the challenge. */\n#define AUTH_FLAG_OPAQUE_PARAM (0x0001)\n/* Used if this Authentication-Info may be sent for non-40[17]\n * response for this protocol. */\n#define AUTH_FLAG_VERIFY_NON40x (0x0002)\n/* Used for broken the connection-based auth schemes. */\n#define AUTH_FLAG_CONN_AUTH (0x0004)\n\nstruct auth_protocol {\n    unsigned id; /* public NE_AUTH_* id. */\n\n    int strength; /* protocol strength for sort order. */\n\n    const char *name; /* protocol name. */\n    \n    /* Parse the authentication challenge; returns zero on success, or\n     * non-zero if this challenge be handled.  'attempt' is the number\n     * of times the request has been resent due to auth challenges.\n     * On failure, challenge_error() should be used to append an error\n     * message to the error buffer 'errmsg'. */\n    int (*challenge)(auth_session *sess, int attempt,\n                     struct auth_challenge *chall,\n                     const char *target, ne_buffer **errmsg);\n\n    /* Return the string to send in the -Authenticate request header:\n     * (ne_malloc-allocated, NUL-terminated string) */\n    char *(*response)(auth_session *sess, struct auth_request *req);\n    \n    /* Parse a Authentication-Info response; returns NE_* error code\n     * on failure; on failure, the session error string must be\n     * set. */\n    int (*verify)(struct auth_request *req, auth_session *sess,\n                  const char *value);\n    \n    int flags; /* AUTH_FLAG_* flags */\n};\n\n/* Helper function to append an error to the buffer during challenge\n * handling.  Pass printf-style string.  *errmsg may be NULL and is\n * allocated if necessary.  errmsg must be non-NULL. */\nstatic void challenge_error(ne_buffer **errmsg, const char *fmt, ...)\n    ne_attribute((format(printf, 2, 3)));\n\nstatic int inside_domain(auth_session *sess, const char *req_uri);\n\n/* Free the domains array, precondition sess->ndomains > 0. */\nstatic void free_domains(auth_session *sess)\n{\n    do {\n        ne_free(sess->domains[sess->ndomains - 1]);\n    } while (--sess->ndomains);\n    ne_free(sess->domains);\n    sess->domains = NULL;\n}\n\nstatic void clean_session(auth_session *sess) \n{\n    if (sess->basic) zero_and_free(sess->basic);\n    if (sess->nonce) ne_free(sess->nonce);\n    if (sess->cnonce) ne_free(sess->cnonce);\n    if (sess->opaque) ne_free(sess->opaque);\n    if (sess->realm) ne_free(sess->realm);\n    if (sess->userhash) ne_free(sess->userhash);\n    if (sess->username_star) ne_free(sess->username_star);\n    if (sess->response_rhs) ne_free(sess->response_rhs);\n    if (sess->h_a1) zero_and_free(sess->h_a1);\n    sess->realm = sess->basic = sess->cnonce = sess->nonce =\n        sess->opaque = sess->userhash = sess->response_rhs =\n        sess->h_a1 = sess->username_star = NULL;\n    if (sess->ndomains) free_domains(sess);\n#ifdef HAVE_GSSAPI\n    {\n        unsigned int major;\n\n        if (sess->gssctx != GSS_C_NO_CONTEXT)\n            gss_delete_sec_context(&major, &sess->gssctx, GSS_C_NO_BUFFER);\n        \n    }\n    if (sess->gssapi_token) ne_free(sess->gssapi_token);\n    sess->gssapi_token = NULL;\n#endif\n#ifdef HAVE_SSPI\n    if (sess->sspi_token) ne_free(sess->sspi_token);\n    sess->sspi_token = NULL;\n    ne_sspi_destroy_context(sess->sspi_context);\n    sess->sspi_context = NULL;\n#endif\n#ifdef NE_HAVE_NTLM\n    if (sess->ntlm_token) zero_and_free(sess->ntlm_token);\n    if (sess->ntlm_password) zero_and_free(sess->ntlm_password);\n#endif\n\n    sess->protocol = NULL;\n}\n\n/* Callback to retrieve user credentials for given session on given\n * attempt (pre request) for given challenge.  Password is written to\n * pwbuf (of size ABUFSIZE).  On error, challenge_error() is used\n * with errmsg. */\nstatic int get_credentials(auth_session *sess, ne_buffer **errmsg, int attempt,\n                           struct auth_challenge *chall, char *pwbuf)\n{\n    char *realm = sess->realm ? ne_strclean(ne_strdup(sess->realm)) : \"\";\n    unsigned mask = chall->protocol->id | sess->spec->protomask;\n    int rv;\n\n    if (chall->handler->new_creds)\n        rv = chall->handler->new_creds(chall->handler->userdata,\n                                       attempt, mask, realm,\n                                       sess->username, pwbuf,\n                                       ABUFSIZE);\n    else\n        rv = chall->handler->old_creds(chall->handler->userdata, realm,\n                                       chall->handler->attempt++, sess->username, pwbuf);\n\n    if (sess->realm) ne_free(realm);\n\n    if (rv == 0)\n        return 0;\n\n    challenge_error(errmsg, _(\"rejected %s challenge\"),\n                    chall->protocol->name);\n    return -1;\n}\n\n/* Return the scope of the Basic authentication domain following rule\n * in RFC 7617.  Malloc-allocated path is returned. */\nstatic char *get_scope_path(const char *uri)\n{\n    ne_uri base, udot, parent;\n    char *s;\n\n    memset(&udot, 0, sizeof udot);\n    udot.path = \".\";\n\n    if (ne_uri_parse(uri, &base) != 0) {\n        /* Assume scope is whole origin. */\n        return ne_strdup(\"/\");\n    }\n\n    ne_uri_resolve(&base, &udot, &parent);\n\n    s = parent.path;\n    parent.path = NULL;\n\n    ne_uri_free(&parent);\n    ne_uri_free(&base);\n\n    return s;\n}\n\n/* Examine a Basic auth challenge.\n * Returns 0 if an valid challenge, else non-zero. */\nstatic int basic_challenge(auth_session *sess, int attempt,\n                           struct auth_challenge *parms,\n                           const char *target, ne_buffer **errmsg)\n{\n    char *tmp, password[ABUFSIZE];\n\n    /* Verify challenge... must have a realm */\n    if (parms->realm == NULL) {\n        challenge_error(errmsg, _(\"missing realm in Basic challenge\"));\n\treturn -1;\n    }\n\n    clean_session(sess);\n    \n    sess->realm = ne_strdup(parms->realm);\n\n    if (get_credentials(sess, errmsg, attempt, parms, password)) {\n\t/* Failed to get credentials */\n\treturn -1;\n    }\n\n    if (strchr(sess->username, ':') != NULL) {\n        challenge_error(errmsg, _(\"cannot handle Basic challenge \"\n                                  \"for username containing colon\"));\n        return -1;\n    }\n\n    tmp = ne_concat(sess->username, \":\", password, NULL);\n    sess->basic = ne_base64((unsigned char *)tmp, strlen(tmp));\n    zero_and_free(tmp);\n\n    ne__strzero(password, sizeof password);\n\n    if (strcmp(target, \"*\") == 0 || sess->context == AUTH_CONNECT) {\n        /* For CONNECT, or if the request-target is \"*\", the auth\n         * scope is implicitly the whole server. */\n        return 0;\n    }\n\n    sess->domains = ne_malloc(sizeof *sess->domains);\n    sess->domains[0] = get_scope_path(target);\n    sess->ndomains = 1;\n\n    NE_DEBUG(NE_DBG_HTTPAUTH, \"auth: Basic auth scope is: %s\\n\",\n             sess->domains[0]);\n\n    return 0;\n}\n\n/* Add Basic authentication credentials to a request */\nstatic char *request_basic(auth_session *sess, struct auth_request *req) \n{\n    if (sess->ndomains && !inside_domain(sess, req->target)) {\n        return NULL;\n    }\n\n    return ne_concat(\"Basic \", sess->basic, \"\\r\\n\", NULL);\n}\n\n#ifdef HAVE_GSSAPI\n/* Add GSSAPI authentication credentials to a request */\nstatic char *request_negotiate(auth_session *sess, struct auth_request *req)\n{\n    if (sess->gssapi_token) \n        return ne_concat(\"Negotiate \", sess->gssapi_token, \"\\r\\n\", NULL);\n    else\n        return NULL;\n}\n\n/* Create an GSSAPI name for server HOSTNAME; returns non-zero on\n * error. */\nstatic void get_gss_name(gss_name_t *server, const char *hostname)\n{\n    unsigned int major, minor;\n    gss_buffer_desc token;\n\n    token.value = ne_concat(\"HTTP@\", hostname, NULL);\n    token.length = strlen(token.value);\n\n    major = gss_import_name(&minor, &token, GSS_C_NT_HOSTBASED_SERVICE,\n                            server);\n    ne_free(token.value);\n    \n    if (GSS_ERROR(major)) {\n        NE_DEBUG(NE_DBG_HTTPAUTH, \"gssapi: gss_import_name failed.\\n\");\n        *server = GSS_C_NO_NAME;\n    }\n}\n\n/* Append GSSAPI error(s) for STATUS of type TYPE to BUF; prepending\n * \": \" to each error if *FLAG is non-zero, setting *FLAG after an\n * error has been appended. */\nstatic void make_gss_error(ne_buffer *buf, int *flag,\n                           unsigned int status, int type)\n{\n    unsigned int major, minor;\n    unsigned int context = 0;\n    \n    do {\n        gss_buffer_desc msg;\n        major = gss_display_status(&minor, status, type,\n                                   GSS_C_NO_OID, &context, &msg);\n        if (major == GSS_S_COMPLETE && msg.length) {\n            if ((*flag)++) ne_buffer_append(buf, \": \", 2);\n            ne_buffer_append(buf, msg.value, msg.length);\n        }\n        if (msg.length) gss_release_buffer(&minor, &msg);\n    } while (context);\n}\n\n/* Continue a GSS-API Negotiate exchange, using input TOKEN if\n * non-NULL.  Returns non-zero on error, in which case *errmsg is\n * guaranteed to be non-NULL (i.e. an error message is set). */\nstatic int continue_negotiate(auth_session *sess, const char *token,\n                              ne_buffer **errmsg)\n{\n    unsigned int major, minor;\n    gss_buffer_desc input = GSS_C_EMPTY_BUFFER;\n    gss_buffer_desc output = GSS_C_EMPTY_BUFFER;\n    unsigned char *bintoken = NULL;\n    int ret;\n\n    if (token) {\n        input.length = ne_unbase64(token, &bintoken);\n        if (input.length == 0) {\n            challenge_error(errmsg, _(\"invalid Negotiate token\"));\n            return -1;\n        }\n        input.value = bintoken;\n        NE_DEBUG(NE_DBG_HTTPAUTH, \"gssapi: Continuation token [%s]\\n\", token);\n    }\n    else if (sess->gssctx != GSS_C_NO_CONTEXT) {\n        NE_DEBUG(NE_DBG_HTTPAUTH, \"gssapi: Reset incomplete context.\\n\");\n        gss_delete_sec_context(&minor, &sess->gssctx, GSS_C_NO_BUFFER);\n    }\n\n    major = gss_init_sec_context(&minor, GSS_C_NO_CREDENTIAL, &sess->gssctx,\n                                 sess->gssname, sess->gssmech, \n                                 GSS_C_MUTUAL_FLAG, GSS_C_INDEFINITE, \n                                 GSS_C_NO_CHANNEL_BINDINGS,\n                                 &input, &sess->gssmech, &output, NULL, NULL);\n\n    /* done with the input token. */\n    if (bintoken) ne_free(bintoken);\n\n    if (GSS_ERROR(major)) {\n        int flag = 0;\n\n        challenge_error(errmsg, _(\"GSSAPI authentication error: \"));\n        make_gss_error(*errmsg, &flag, major, GSS_C_GSS_CODE);\n        make_gss_error(*errmsg, &flag, minor, GSS_C_MECH_CODE);\n\n        return -1;\n    }\n\n    if (major == GSS_S_CONTINUE_NEEDED || major == GSS_S_COMPLETE) {\n        NE_DEBUG(NE_DBG_HTTPAUTH, \"gssapi: init_sec_context OK. (major=%d)\\n\",\n                 major);\n        ret = 0;\n    } \n    else {\n        challenge_error(errmsg, _(\"GSSAPI failure (code %u)\"), major);\n        ret = -1;\n    }\n\n    if (major != GSS_S_CONTINUE_NEEDED) {\n        /* context no longer needed: destroy it */\n        gss_delete_sec_context(&minor, &sess->gssctx, GSS_C_NO_BUFFER);\n    }\n\n    if (output.length) {\n        sess->gssapi_token = ne_base64(output.value, output.length);\n        NE_DEBUG(NE_DBG_HTTPAUTH, \"gssapi: Output token: [%s]\\n\", \n                 sess->gssapi_token);\n        gss_release_buffer(&minor, &output);\n    } else {\n        NE_DEBUG(NE_DBG_HTTPAUTH, \"gssapi: No output token.\\n\");\n    }\n\n    return ret;\n}\n\n/* Process a Negotiate challenge CHALL in session SESS; returns zero\n * if challenge is accepted. */\nstatic int negotiate_challenge(auth_session *sess, int attempt,\n                               struct auth_challenge *chall,\n                               const char *target, ne_buffer **errmsg)\n{\n    const char *token = chall->opaque;\n\n    /* Respect an initial challenge - which must have no input token,\n     * or a continuation - which must have an input token. */\n    if (attempt == 0 || token) {\n        return continue_negotiate(sess, token, errmsg);\n    }\n    else {\n        challenge_error(errmsg, _(\"ignoring empty Negotiate continuation\"));\n        return -1;\n    }\n}\n\n/* Verify the header HDR in a Negotiate response. */\nstatic int verify_negotiate_response(struct auth_request *req, auth_session *sess,\n                                     const char *hdr)\n{\n    char *duphdr = ne_strdup(hdr);\n    char *sep, *ptr = strchr(duphdr, ' ');\n    int ret;\n    ne_buffer *errmsg = NULL;\n\n    if (!ptr || strncmp(hdr, \"Negotiate\", ptr - duphdr) != 0) {\n        ne_set_error(sess->sess, _(\"Negotiate response verification failed: \"\n                                   \"invalid response header token\"));\n        ne_free(duphdr);\n        return NE_ERROR;\n    }\n    \n    ptr++;\n\n    if (strlen(ptr) == 0) {\n        NE_DEBUG(NE_DBG_HTTPAUTH, \"gssapi: No token in Negotiate response!\\n\");\n        ne_free(duphdr);\n        return NE_OK;\n    }\n\n    if ((sep = strchr(ptr, ',')) != NULL)\n        *sep = '\\0';\n    if ((sep = strchr(ptr, ' ')) != NULL)\n        *sep = '\\0';\n\n    NE_DEBUG(NE_DBG_HTTPAUTH, \"gssapi: Negotiate response token [%s]\\n\", ptr);\n    ret = continue_negotiate(sess, ptr, &errmsg);\n    if (ret) {\n        ne_set_error(sess->sess, _(\"Negotiate response verification failure: %s\"),\n                     errmsg->data);\n    }\n\n    if (errmsg) ne_buffer_destroy(errmsg);\n    ne_free(duphdr);\n\n    return ret ? NE_ERROR : NE_OK;\n}\n#endif\n\n#ifdef HAVE_SSPI\nstatic char *request_sspi(auth_session *sess, struct auth_request *request) \n{\n    if (sess->sspi_token)\n        return ne_concat(sess->protocol->name, \" \", sess->sspi_token, \"\\r\\n\", NULL);\n    else\n        return NULL;\n}\n\nstatic int continue_sspi(auth_session *sess, int ntlm, const char *hdr)\n{\n    int status;\n    char *response = NULL;\n    \n    NE_DEBUG(NE_DBG_HTTPAUTH, \"auth: SSPI challenge.\\n\");\n    \n    if (!sess->sspi_context) {\n        status = ne_sspi_create_context(&sess->sspi_context, sess->sspi_host, ntlm);\n        if (status) {\n            return status;\n        }\n    }\n    \n    status = ne_sspi_authenticate(sess->sspi_context, hdr, &response);\n    if (status) {\n        return status;\n    }\n\n    if (response && *response) {\n        sess->sspi_token = response;\n        \n        NE_DEBUG(NE_DBG_HTTPAUTH, \"auth: SSPI challenge [%s]\\n\", sess->sspi_token);\n    }\n\n    return 0;\n}\n\nstatic int sspi_challenge(auth_session *sess, int attempt,\n                          struct auth_challenge *parms,\n                          const char *target, ne_buffer **errmsg)\n{\n    int ntlm = ne_strcasecmp(parms->protocol->name, \"NTLM\") == 0;\n\n    return continue_sspi(sess, ntlm, parms->opaque);\n}\n\nstatic int verify_sspi(struct auth_request *req, auth_session *sess,\n                       const char *hdr)\n{\n    int ntlm = ne_strncasecmp(hdr, \"NTLM \", 5) == 0;\n    char *ptr = strchr(hdr, ' ');\n\n    if (!ptr) {\n        ne_set_error(sess->sess, _(\"SSPI response verification failed: \"\n                                   \"invalid response header token\"));\n        return NE_ERROR;\n    }\n\n    while(*ptr == ' ')\n        ptr++;\n\n    if (*ptr == '\\0') {\n        NE_DEBUG(NE_DBG_HTTPAUTH, \"auth: No token in SSPI response!\\n\");\n        return NE_OK;\n    }\n\n    return continue_sspi(sess, ntlm, ptr);\n}\n\n#endif\n\n/* Parse the \"domain\" challenge parameter and set the domains array up\n * in the session appropriately. */\nstatic int parse_domain(auth_session *sess, const char *domain)\n{\n    char *cp = ne_strdup(domain), *p = cp;\n    ne_uri base;\n    int invalid = 0;\n\n    memset(&base, 0, sizeof base);\n    ne_fill_server_uri(sess->sess, &base);\n\n    do {\n        char *token = ne_token(&p, ' ');\n        ne_uri rel, absolute;\n\n        if (ne_uri_parse(token, &rel) == 0) {\n            /* Resolve relative to the Request-URI. */\n            base.path = \"/\";\n            ne_uri_resolve(&base, &rel, &absolute);\n\n            /* Compare against the resolved path to check this URI has\n             * the same (scheme, host, port) components; ignore it\n             * otherwise: */\n            base.path = absolute.path;\n            if (absolute.path && ne_uri_cmp(&absolute, &base) == 0) {\n                sess->domains = ne_realloc(sess->domains, \n                                           ++sess->ndomains *\n                                           sizeof(*sess->domains));\n                sess->domains[sess->ndomains - 1] = absolute.path;\n                NE_DEBUG(NE_DBG_HTTPAUTH, \"auth: Using domain %s from %s\\n\",\n                         absolute.path, token);\n                absolute.path = NULL;\n            }\n            else {\n                NE_DEBUG(NE_DBG_HTTPAUTH, \"auth: Ignoring domain %s\\n\",\n                         token);\n            }\n\n            ne_uri_free(&absolute);\n        }\n        else {\n            invalid = 1;\n        }\n        \n        ne_uri_free(&rel);\n        \n    } while (p && !invalid);\n\n    if (invalid && sess->ndomains) {\n        free_domains(sess);\n    }\n\n    ne_free(cp);\n    base.path = NULL;\n    ne_uri_free(&base);\n\n    return invalid;\n}\n\n#ifdef NE_HAVE_NTLM\nstatic char *request_ntlm(auth_session *sess, struct auth_request *request) \n{\n    const char *token = sess->ntlm_token;\n\n    if (token)\n        return ne_concat(sess->protocol->name, \" \", token, \"\\r\\n\", NULL);\n    else\n        return NULL;\n}\n\nstatic const unsigned char ntlm_type2_prefix[] = {\"NTLMSSP\\0\" \"\\02\\0\\0\\0\"};\n#define TYPE2_PREFIX_LEN (sizeof(ntlm_type2_prefix)-1)\n\n#define MIN_TYPE2_LEN (48)\n\n/* Parse a type 2 message from token 'blob', return non-zero on error. */\nstatic int parse_type2_message(tSmbNtlmAuthChallenge *challenge, const char *blob)\n{\n    unsigned char *raw;\n    size_t len = ne_unbase64(blob, &raw);\n    int ret = -1;\n\n    if (len > MIN_TYPE2_LEN && len <= sizeof *challenge\n        && memcmp(raw, ntlm_type2_prefix, TYPE2_PREFIX_LEN) == 0) {\n        memcpy(challenge, raw, len);\n        ret = 0;\n    }\n    if (len) ne_free(raw);\n    return ret;\n}\n\nstatic int ntlm_challenge(auth_session *sess, int attempt,\n                          struct auth_challenge *parms,\n                          const char *target, ne_buffer **errmsg)\n{\n    NE_DEBUG(NE_DBG_HTTPAUTH, \"auth: NTLM challenge (state %d).\\n\",\n             sess->ntlm_state);\n\n    if (sess->ntlm_token) {\n        ne_free(sess->ntlm_token);\n        sess->ntlm_token = NULL;\n    }\n\n    if (!parms->opaque) {\n        NE_DEBUG(NE_DBG_HTTPAUTH, \"auth: NTLM challenge, reset state.\\n\");\n        sess->ntlm_state = NTLM_INIT;\n    }\n    else if (sess->ntlm_state == NTLM_INIT) {\n        challenge_error(errmsg, _(\"unexpected token in NTLM challenge\"));\n        return -1;\n    }\n\n    if (sess->ntlm_state == NTLM_INIT) {\n        tSmbNtlmAuthRequest req;\n\n        sess->ntlm_password = ne_calloc(NE_ABUFSIZ);\n        if (get_credentials(sess, errmsg, attempt, parms,\n                            sess->ntlm_password)) {\n            /* Failed to get credentials */\n            ne_free(sess->ntlm_password);\n            sess->ntlm_password = NULL;\n            return -1;\n        }\n\n        /* Libntlm uses some default flags in the type 1 message which\n         * are possibly not appropriate, it would be better to\n         * manipulate via an API call. */\n        buildSmbNtlmAuthRequest(&req, sess->username, NULL);\n        sess->ntlm_token = ne_base64((void *)&req, SmbLength(&req));\n        sess->ntlm_state = NTLM_SENT;\n    }\n    else if (sess->ntlm_state == NTLM_SENT) {\n        tSmbNtlmAuthChallenge chall;\n        tSmbNtlmAuthResponse resp;\n\n        if (parse_type2_message(&chall, parms->opaque)) {\n            challenge_error(errmsg, _(\"malformed NTLM challenge\"));\n            return -1;\n        }\n\n#ifdef NE_DEBUGGING\n        if (ne_debug_mask & NE_DBG_HTTPAUTH) {\n            NE_DEBUG(NE_DBG_HTTPAUTH, \"auth: NTLM type 2 message - \");\n            dumpSmbNtlmAuthChallenge(ne_debug_stream, &chall);\n        }\n#endif\n\n        /* Build type 3 message: */\n        buildSmbNtlmAuthResponse(&chall, &resp, sess->username,\n                                 sess->ntlm_password);\n        sess->ntlm_token = ne_base64((void *)&resp, SmbLength(&resp));\n        sess->ntlm_state = NTLM_DONE;\n    }\n    else {\n        challenge_error(errmsg, _(\"could not handle NTLM challenge\"));\n        return -1;\n    }\n\n    return 0;\n}\n#endif /* HAVE_NTLM */\n\n/* Generated with 'mktable safe_username', do not alter here -- */\nstatic const unsigned char table_safe_username[256] = {\n/* x00 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,\n/* x10 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n/* x20 */ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n/* x30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n/* x40 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n/* x50 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,\n/* x60 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n/* x70 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,\n/* x80 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n/* x90 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n/* xA0 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n/* xB0 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n/* xC0 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n/* xD0 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n/* xE0 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n/* xF0 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1\n}; /* -- Generated code from 'mktable safe_username' ends. */\n\n/* Returns non-zero if 'username' is unsafe to use without quoting. */\nstatic int unsafe_username(const char *username)\n{\n    const char *p;\n    int rv = 0;\n\n    for (p = username; *p; p++)\n        rv |= table_safe_username[(const unsigned char)*p];\n\n    return rv;\n}\n\n/* Returns the H(username:realm:password) used in the Digest H(A1)\n * calculation. */\nstatic char *get_digest_h_urp(auth_session *sess, ne_buffer **errmsg,\n                              int attempt, struct auth_challenge *parms)\n{\n    char password[ABUFSIZE], *h_urp;\n\n    if (get_credentials(sess, errmsg, attempt, parms, password)) {\n        /* Failed to get credentials */\n        return NULL;\n    }\n\n    /* Calculate userhash for this (realm, username) if required.\n     * https://tools.ietf.org/html/rfc7616#section-3.4.4 */\n    if (parms->userhash == userhash_true) {\n        sess->userhash = ne_strhash(parms->alg->hash, sess->username, \":\",\n                                    sess->realm, NULL);\n    }\n    else {\n        /* Without userhash, for usernames which need some kind of\n         * escaping, either: a) username* must be supported, which\n         * is known if the server sent userhash=false, *and* the\n         * caller has indicated the username really is UTF-8; or\n         * else b) the challenge is an error since the username\n         * cannot be sent safely. */\n        if (unsafe_username(sess->username)) {\n            if (parms->userhash == userhash_none\n                || parms->handler->new_creds == NULL) {\n                challenge_error(errmsg, _(\"could not handle non-ASCII \"\n                                          \"username in Digest challenge\"));\n                ne__strzero(password, sizeof password);\n                return NULL;\n            }\n            sess->username_star = ne_strparam(\"UTF-8\", NULL, (unsigned char *)sess->username);\n            NE_DEBUG(NE_DBG_HTTPAUTH, \"auth: Using username* => %s\\n\", sess->username_star);\n        }\n    }\n\n    /* H(A1) calculation identical for 2069 or 2617/7616:\n     * https://tools.ietf.org/html/rfc7616#section-3.4.2 */\n    h_urp = ne_strhash(parms->alg->hash, sess->username, \":\", sess->realm, \":\",\n                       password, NULL);\n    ne__strzero(password, sizeof password);\n\n    return h_urp;\n}\n\n/* Examine a digest challenge: return 0 if it is a valid Digest challenge,\n * else non-zero. */\nstatic int digest_challenge(auth_session *sess, int attempt,\n                            struct auth_challenge *parms,\n                            const char *target, ne_buffer **errmsg)\n{\n    char *p, *h_urp = NULL;\n\n    if (parms->alg == NULL) {\n        challenge_error(errmsg, _(\"unknown algorithm in Digest challenge\"));\n        return -1;\n    }\n\n    /* qop= is mandatory from 2617 onward, fail w/o LEGACY_DIGEST */\n    if (!parms->got_qop\n        && ((parms->handler->protomask & NE_AUTH_LEGACY_DIGEST) == 0)) {\n        challenge_error(errmsg, _(\"legacy Digest challenge not supported\"));\n        return -1;\n    }\n    else if (parms->alg->sess && !parms->qop_auth) {\n        challenge_error(errmsg, _(\"incompatible algorithm in Digest challenge\"));\n        return -1;\n    }\n    else if (parms->realm == NULL || parms->nonce == NULL) {\n        challenge_error(errmsg, _(\"missing parameter in Digest challenge\"));\n\treturn -1;\n    }\n    else if (parms->stale && sess->realm == NULL) {\n        challenge_error(errmsg, _(\"initial Digest challenge was stale\"));\n        return -1;\n    }\n    else if (parms->stale && (sess->alg != parms->alg\n                              || strcmp(sess->realm, parms->realm))) {\n        /* With stale=true the realm and algorithm cannot change since these\n         * require re-hashing H(A1) which defeats the point. */\n        challenge_error(errmsg, _(\"stale Digest challenge with new algorithm or realm\"));\n        return -1;\n    }\n\n    p = ne_strhash(parms->alg->hash, \"\", NULL);\n    if (p == NULL) {\n        challenge_error(errmsg,\n                        _(\"%s algorithm in Digest challenge not supported\"),\n                        parms->alg->name);\n        return -1;\n    }\n    ne_free(p);\n\n    if (!parms->stale) {\n        unsigned char nonce[32];\n\n        /* Non-stale challenge: clear session and request credentials. */\n        clean_session(sess);\n\n        /* The domain parameter must be parsed after the session is\n         * cleaned; ignore domain for proxy auth. */\n        if (parms->domain && sess->spec == &ah_server_class\n            && parse_domain(sess, parms->domain)) {\n            challenge_error(errmsg, _(\"could not parse domain in Digest challenge\"));\n            return -1;\n        }\n\n        /* Create the client nonce. */\n        if ((ne_mknonce(nonce, sizeof nonce, 0))) {\n            challenge_error(errmsg,\n                            _(\"cannot create client nonce for Digest challenge\"));\n            return -1;\n        }\n        sess->cnonce = ne_base64(nonce, sizeof nonce);\n\n        sess->realm = ne_strdup(parms->realm);\n        sess->alg = parms->alg;\n\n        h_urp = get_digest_h_urp(sess, errmsg, attempt, parms);\n        if (h_urp == NULL) {\n            return -1;\n        }\n    }\n    else {\n        /* Stale challenge: accept a new nonce or opaque. */\n        if (sess->nonce) ne_free(sess->nonce);\n        if (sess->opaque && parms->opaque) ne_free(sess->opaque);\n    }\n    \n    sess->nonce = ne_strdup(parms->nonce);\n    if (parms->opaque) {\n\tsess->opaque = ne_strdup(parms->opaque);\n    }\n    \n    if (parms->got_qop) {\n\t/* What type of qop are we to apply to the message? */\n\tNE_DEBUG(NE_DBG_HTTPAUTH, \"auth: Got qop, using 2617-style.\\n\");\n\tsess->nonce_count = 0;\n        sess->qop = auth_qop_auth;\n    } else {\n\t/* No qop at all/ */\n\tsess->qop = auth_qop_none;\n    }\n\n    if (h_urp) {\n        if (sess->alg->sess) {\n            sess->h_a1 = ne_strhash(parms->alg->hash, h_urp, \":\",\n                                    sess->nonce, \":\", sess->cnonce, NULL);\n            zero_and_free(h_urp);\n            NE_DEBUG(NE_DBG_HTTPAUTH, \"auth: Session H(A1) is [%s]\\n\", sess->h_a1);\n        }\n        else {\n            sess->h_a1 = h_urp;\n            NE_DEBUG(NE_DBG_HTTPAUTH, \"auth: H(A1) is [%s]\\n\", sess->h_a1);\n        }\n    }\n    \n    NE_DEBUG(NE_DBG_HTTPAUTH, \"auth: Accepting digest challenge.\\n\");\n\n    return 0;\n}\n\n/* Returns non-zero if given request-target is inside the\n * authentication domain defined for the session. */\nstatic int inside_domain(auth_session *sess, const char *target)\n{\n    int inside = 0;\n    size_t n;\n    ne_uri uri;\n    \n    /* Parse the Request-URI; it will be an absoluteURI if using a\n     * proxy, and possibly '*'. */\n    if (strcmp(target, \"*\") == 0 || ne_uri_parse(target, &uri) != 0) {\n        /* Presume outside the authentication domain. */\n        return 0;\n    }\n\n    for (n = 0; n < sess->ndomains && !inside; n++) {\n        const char *d = sess->domains[n];\n        \n        inside = strncmp(uri.path, d, strlen(d)) == 0;\n    }\n    \n    NE_DEBUG(NE_DBG_HTTPAUTH, \"auth: '%s' is inside auth domain: %d.\\n\", \n             uri.path, inside);\n    ne_uri_free(&uri);\n    \n    return inside;\n}            \n\n/* Return Digest authentication credentials header value for the given\n * session. */\nstatic char *request_digest(auth_session *sess, struct auth_request *req) \n{\n    char *h_a2, *response;\n    char nc_value[9] = {0};\n    const char *qop_value = \"auth\"; /* qop-value */\n    ne_buffer *ret;\n    unsigned int hash = sess->alg->hash;\n\n    /* Do not submit credentials if an auth domain is defined and this\n     * request-uri fails outside it. */\n    if (sess->ndomains && !inside_domain(sess, req->target)) {\n        return NULL;\n    }\n\n    /* H(A2): https://tools.ietf.org/html/rfc7616#section-3.4.3 - Note\n     * that the RFC specifies that \"request-uri\" is used in the A2\n     * grammar, which matches the RFC 9112 'request-target', which is\n     * what was passed through by ah_create. */\n    h_a2 = ne_strhash(hash, req->method, \":\", req->target, NULL);\n    NE_DEBUG(NE_DBG_HTTPAUTH, \"auth: H(A2): %s\\n\", h_a2);\n\n    /* Calculate the 'response' to the Digest challenge to send the\n     * server in the request. */\n    if (sess->qop == auth_qop_none) {\n        /* RFC 2069 case,\n         * https://tools.ietf.org/html/rfc2069#section-2.1.2 */\n        response = ne_strhash(hash, sess->h_a1, \":\", sess->nonce,\n                              \":\", h_a2, NULL);\n    } else {\n        /* For RFC 2617/7616-style; part of this calculation will be\n         * needed again when verifying the (Proxy-)Authentication-Info\n         * response header; that part is cached in sess->response_rhs.\n         * https://tools.ietf.org/html/rfc7616#section-3.4.1 */\n        sess->nonce_count++;\n        ne_snprintf(nc_value, 9, \"%08x\", sess->nonce_count);\n\n        if (sess->response_rhs) ne_free(sess->response_rhs);\n        sess->response_rhs = ne_concat(sess->nonce, \":\",\n                                       nc_value, \":\", sess->cnonce, \":\",\n                                       qop_value, NULL);\n        response = ne_strhash(hash, sess->h_a1, \":\",\n                              sess->response_rhs, \":\", h_a2, NULL);\n    }\n\n    ret = ne_buffer_create();\n\n    ne_buffer_concat(ret, \n                     \"Digest realm=\\\"\", sess->realm, \"\\\", \"\n\t\t     \"nonce=\\\"\", sess->nonce, \"\\\", \"\n\t\t     \"uri=\\\"\", req->target, \"\\\", \"\n\t\t     \"response=\\\"\", response, \"\\\", \"\n\t\t     \"algorithm=\\\"\", sess->alg->name, \"\\\"\",\n\t\t     NULL);\n    if (sess->username_star) {\n        ne_buffer_concat(ret, \", username*=\", sess->username_star, NULL);\n    }\n    else {\n        ne_buffer_concat(ret, \", username=\\\"\",\n                         sess->userhash ? sess->userhash : sess->username,\n                         \"\\\"\", NULL);\n    }\n\n    ne_free(response);\n    ne_free(h_a2);\n    \n    if (sess->opaque != NULL) {\n\tne_buffer_concat(ret, \", opaque=\\\"\", sess->opaque, \"\\\"\", NULL);\n    }\n\n    if (sess->qop != auth_qop_none) {\n\t/* Add in cnonce and nc-value fields */\n\tne_buffer_concat(ret, \", cnonce=\\\"\", sess->cnonce, \"\\\", \"\n\t\t\t \"nc=\", nc_value, \", \"\n\t\t\t \"qop=\\\"\", qop_value, \"\\\"\", NULL);\n    }\n    if (sess->userhash) {\n        ne_buffer_czappend(ret, \", userhash=true\");\n    }\n\n    ne_buffer_zappend(ret, \"\\r\\n\");\n\n    return ne_buffer_finish(ret);\n}\n\n/* Parse line of comma-separated key-value pairs.  If 'ischall' == 1,\n * then also return a leading space-separated token, as *value ==\n * NULL.  Otherwise, if return value is 0, *key and *value will be\n * non-NULL.  If return value is non-zero, parsing has ended.  If\n * 'sep' is non-NULL and ischall is 1, the separator character is\n * written to *sep when a challenge is parsed. */\nstatic int tokenize(char **hdr, char **key, char **value, char *sep,\n                    int ischall)\n{\n    char *pnt = *hdr;\n    enum { BEFORE_EQ, AFTER_EQ, AFTER_EQ_QUOTED } state = BEFORE_EQ;\n    \n    if (**hdr == '\\0')\n\treturn 1;\n\n    *key = NULL;\n\n    do {\n\tswitch (state) {\n\tcase BEFORE_EQ:\n\t    if (*pnt == '=') {\n\t\tif (*key == NULL)\n\t\t    return -1;\n\t\t*pnt = '\\0';\n\t\t*value = pnt + 1;\n\t\tstate = AFTER_EQ;\n\t    } else if ((*pnt == ' ' || *pnt == ',') \n                       && ischall && *key != NULL) {\n\t\t*value = NULL;\n                if (sep) *sep = *pnt;\n\t\t*pnt = '\\0';\n\t\t*hdr = pnt + 1;\n\t\treturn 0;\n\t    } else if (*key == NULL && strchr(\" \\r\\n\\t\", *pnt) == NULL) {\n\t\t*key = pnt;\n\t    }\n\t    break;\n\tcase AFTER_EQ:\n\t    if (*pnt == ',') {\n\t\t*pnt = '\\0';\n\t\t*hdr = pnt + 1;\n\t\treturn 0;\n\t    } else if (*pnt == '\\\"') {\n\t\tstate = AFTER_EQ_QUOTED;\n\t    }\n\t    break;\n\tcase AFTER_EQ_QUOTED:\n\t    if (*pnt == '\\\"') {\n\t\tstate = AFTER_EQ;\n                *pnt = '\\0';\n\t    }\n\t    break;\n\t}\n    } while (*++pnt != '\\0');\n    \n    if (state == BEFORE_EQ && ischall && *key != NULL) {\n\t*value = NULL;\n        if (sep) *sep = '\\0';\n    }\n\n    *hdr = pnt;\n\n    /* End of string: */\n    return 0;\n}\n\n/* Pass this the value of the 'Authentication-Info:' header field, if\n * one is received.\n * Returns:\n *    0 if it gives a valid authentication for the server \n *    non-zero otherwise (don't believe the response in this case!).\n */\nstatic int verify_digest_response(struct auth_request *req, auth_session *sess,\n                                  const char *value) \n{\n    char *hdr, *pnt, *key, *val;\n    auth_qop qop = auth_qop_none;\n    char *nextnonce, *rspauth, *cnonce, *nc, *qop_value;\n    unsigned int nonce_count;\n    int ret = NE_OK;\n\n    nextnonce = rspauth = cnonce = nc = qop_value = NULL;\n\n    pnt = hdr = ne_strdup(value);\n    \n    NE_DEBUG(NE_DBG_HTTPAUTH, \"auth: Got Auth-Info header: %s\\n\", value);\n\n    while (tokenize(&pnt, &key, &val, NULL, 0) == 0) {\n\tval = ne_shave(val, \"\\\"\");\n\n\tif (ne_strcasecmp(key, \"qop\") == 0) {\n            qop_value = val;\n            if (ne_strcasecmp(val, \"auth\") == 0) {\n\t\tqop = auth_qop_auth;\n\t    } else {\n\t\tqop = auth_qop_none;\n\t    }\n\t} else if (ne_strcasecmp(key, \"nextnonce\") == 0) {\n\t    nextnonce = val;\n\t} else if (ne_strcasecmp(key, \"rspauth\") == 0) {\n\t    rspauth = val;\n\t} else if (ne_strcasecmp(key, \"cnonce\") == 0) {\n\t    cnonce = val;\n\t} else if (ne_strcasecmp(key, \"nc\") == 0) { \n\t    nc = val;\n        }\n    }\n\n    if (qop == auth_qop_none) {\n        /* The 2069-style A-I header only has the entity and nextnonce\n         * parameters. */\n        NE_DEBUG(NE_DBG_HTTPAUTH, \"auth: 2069-style A-I header.\\n\");\n    }\n    else if (!rspauth || !cnonce || !nc) {\n        ret = NE_ERROR;\n        ne_set_error(sess->sess, _(\"Digest mutual authentication failure: \"\n                                   \"missing parameters\"));\n    }\n    else if (strcmp(cnonce, sess->cnonce) != 0) {\n        ret = NE_ERROR;\n        ne_set_error(sess->sess, _(\"Digest mutual authentication failure: \"\n                                   \"client nonce mismatch\"));\n    }\n    else if (nc) {\n        const char *ptr;\n        \n        nonce_count = ne_strhextoul(nc, &ptr);\n        if (*ptr != '\\0' || errno) {\n            ret = NE_ERROR;\n            ne_set_error(sess->sess, _(\"Digest mutual authentication failure: \"\n                                       \"could not parse nonce count\"));\n        }\n        else if (nonce_count != sess->nonce_count) {\n            ret = NE_ERROR;\n            ne_set_error(sess->sess, _(\"Digest mutual authentication failure: \"\n                                       \"nonce count mismatch (%u not %u)\"),\n                         nonce_count, sess->nonce_count);\n        }\n    }\n\n    /* Finally, for qop=auth cases, if everything else is OK, verify\n     * the response-digest field. */    \n    if (qop == auth_qop_auth && ret == NE_OK) {\n        char *h_a2, *response;\n        unsigned int hash = sess->alg->hash;\n\n        h_a2 = ne_strhash(hash, \":\", req->target, NULL);\n        response = ne_strhash(hash, sess->h_a1, \":\", sess->response_rhs,\n                              \":\", h_a2, NULL);\n        ne_free(h_a2);\n        ne_free(sess->response_rhs);\n        sess->response_rhs = NULL;\n\n        /* And... do they match? */\n        ret = ne_strcasecmp(response, rspauth) == 0 ? NE_OK : NE_ERROR;\n        \n        NE_DEBUG(NE_DBG_HTTPAUTH, \"auth: response-digest match: %s \"\n                 \"(expected [%s] vs actual [%s])\\n\", \n                 ret == NE_OK ? \"yes\" : \"no\", response, rspauth);\n\n        if (ret) {\n            ne_set_error(sess->sess, _(\"Digest mutual authentication failure: \"\n                                       \"request-digest mismatch\"));\n        }\n\n        ne_free(response);\n    }\n\n    /* Check for a nextnonce */\n    if (nextnonce != NULL) {\n\tNE_DEBUG(NE_DBG_HTTPAUTH, \"auth: Found nextnonce of [%s].\\n\", nextnonce);\n        ne_free(sess->nonce);\n\tsess->nonce = ne_strdup(nextnonce);\n        sess->nonce_count = 0;\n    }\n\n    ne_free(hdr);\n\n    return ret;\n}\n\nstatic const struct auth_protocol protocols[] = {\n    { NE_AUTH_BASIC, 10, \"Basic\",\n      basic_challenge, request_basic, NULL,\n      0 },\n    { NE_AUTH_DIGEST, 20, \"Digest\",\n      digest_challenge, request_digest, verify_digest_response,\n      0 },\n#ifdef HAVE_GSSAPI\n    { NE_AUTH_GSSAPI_ONLY, 30, \"Negotiate\",\n      negotiate_challenge, request_negotiate, verify_negotiate_response,\n      AUTH_FLAG_OPAQUE_PARAM|AUTH_FLAG_VERIFY_NON40x|AUTH_FLAG_CONN_AUTH },\n#endif\n#ifdef HAVE_SSPI\n    { NE_AUTH_NTLM, 30, \"NTLM\",\n      sspi_challenge, request_sspi, NULL,\n      AUTH_FLAG_OPAQUE_PARAM|AUTH_FLAG_VERIFY_NON40x|AUTH_FLAG_CONN_AUTH },\n    { NE_AUTH_SSPI, 30, \"Negotiate\",\n      sspi_challenge, request_sspi, verify_sspi,\n      AUTH_FLAG_OPAQUE_PARAM|AUTH_FLAG_VERIFY_NON40x|AUTH_FLAG_CONN_AUTH },\n#endif\n#ifdef NE_HAVE_NTLM\n    { NE_AUTH_NTLM, 30, \"NTLM\",\n      ntlm_challenge, request_ntlm, NULL,\n      AUTH_FLAG_OPAQUE_PARAM|AUTH_FLAG_VERIFY_NON40x|AUTH_FLAG_CONN_AUTH },\n#endif\n    { 0 }\n};\n\n/* Insert a new auth challenge 'chall' into list of challenges 'list'.\n * The challenge list is kept in sorted order of strength, with\n * highest strength first. */\nstatic void insert_challenge(struct auth_challenge **list,\n                             struct auth_challenge *chall)\n{\n    struct auth_challenge **p;\n\n    for (p = list; *p != NULL; p = &(*p)->next) {\n        if (chall->protocol->strength > (*p)->protocol->strength\n            || ((*p)->protocol->id == NE_AUTH_DIGEST\n                && chall->protocol->id == NE_AUTH_DIGEST\n                && chall->alg && (*p)->alg\n                && chall->alg->hash > (*p)->alg->hash)) {\n            break;\n        }\n    }\n\n    chall->next = *p;\n    *p = chall;\n}\n\nstatic void challenge_error(ne_buffer **errbuf, const char *fmt, ...)\n{\n    char err[128];\n    va_list ap;\n    size_t len;\n    \n    va_start(ap, fmt);\n    len = ne_vsnprintf(err, sizeof err, fmt, ap);\n    va_end(ap);\n    NE_DEBUG(NE_DBG_HTTPAUTH, \"auth: Challenge error: %s\\n\", err);\n\n    if (*errbuf == NULL) {\n        *errbuf = ne_buffer_create();\n        ne_buffer_append(*errbuf, err, len);\n    }\n    else {\n        ne_buffer_concat(*errbuf, \", \", err, NULL);\n    }\n}\n\n/* Passed the value of a \"(Proxy,WWW)-Authenticate: \" header field.\n * Returns 0 if valid challenge was accepted; non-zero if no valid\n * challenge was found. */\nstatic int auth_challenge(auth_session *sess, int attempt, const char *uri,\n                          const char *value) \n{\n    char *pnt, *key, *val, *hdr, sep;\n    struct auth_challenge *chall = NULL, *challenges = NULL;\n    ne_buffer *errmsg = NULL;\n\n    pnt = hdr = ne_strdup(value); \n\n    /* The header value may be made up of one or more challenges.  We\n     * split it down into attribute-value pairs, then search for\n     * schemes in the pair keys. */\n\n    while (!tokenize(&pnt, &key, &val, &sep, 1)) {\n\n\tif (val == NULL) {\n            /* Special case, challenge token, not key=value pair: */\n            const struct auth_protocol *proto = NULL;\n            struct auth_handler *hdl;\n            size_t n;\n\n            /* Accumulated challenge is now completed and can be\n             * inserted into the list. */\n            if (chall) {\n                insert_challenge(&challenges, chall);\n                chall = NULL;\n            }\n\n            for (hdl = sess->handlers; hdl; hdl = hdl->next) {\n                for (n = 0; protocols[n].id; n++) {\n                    if (protocols[n].id & hdl->protomask\n                        && ne_strcasecmp(key, protocols[n].name) == 0) {\n                        proto = &protocols[n];\n                        break;\n                    }\n                }\n                if (proto) break;\n            }\n\n            if (proto == NULL) {\n                /* Ignore this challenge. */\n                challenge_error(&errmsg, _(\"ignored %s challenge\"), key);\n                continue;\n\t    }\n            \n            NE_DEBUG(NE_DBG_HTTPAUTH, \"auth: Got '%s' challenge.\\n\", proto->name);\n            chall = ne_calloc(sizeof *chall);\n            chall->protocol = proto;\n            chall->handler = hdl;\n            chall->alg = HASHALG_MD5; /* RFC default is MD5 */\n\n            if ((proto->flags & AUTH_FLAG_OPAQUE_PARAM) && sep == ' ') {\n                /* Cope with the fact that the unquoted base64\n                 * parameter token doesn't match the 2617 auth-param\n                 * grammar: */\n                chall->opaque = ne_shave(ne_token(&pnt, ','), \" \\t\");\n                NE_DEBUG(NE_DBG_HTTPAUTH, \"auth: %s opaque parameter '%s'\\n\",\n                         proto->name, chall->opaque);\n                if (!pnt) break; /* stop parsing at end-of-string. */\n            }\n\t    continue;\n\t} else if (chall == NULL) {\n\t    /* Ignore pairs for an unknown challenge. */\n            NE_DEBUG(NE_DBG_HTTPAUTH, \"auth: Ignored parameter: %s = %s\\n\", key, val);\n\t    continue;\n\t}\n\n\t/* Strip quotes off value. */\n\tval = ne_shave(val, \"\\\"'\");\n\n\tif (ne_strcasecmp(key, \"realm\") == 0) {\n\t    chall->realm = val;\n\t} else if (ne_strcasecmp(key, \"nonce\") == 0) {\n\t    chall->nonce = val;\n\t} else if (ne_strcasecmp(key, \"opaque\") == 0) {\n\t    chall->opaque = val;\n\t} else if (ne_strcasecmp(key, \"stale\") == 0) {\n\t    /* Truth value */\n\t    chall->stale = (ne_strcasecmp(val, \"true\") == 0);\n\t} else if (ne_strcasecmp(key, \"algorithm\") == 0) {\n            unsigned int n;\n\n            chall->alg = NULL; /* left unset for unknown algorithm. */\n            for (n = 0; n < NUM_HASHALGS; n++) {\n                if (ne_strcasecmp(val, hashalgs[n].name) == 0) {\n                    chall->alg = &hashalgs[n];\n                    break;\n                }\n            }\n\n            NE_DEBUG(NE_DBG_HTTPAUTH, \"auth: Mapped '%s' to algorithm %s\\n\", val,\n                     chall->alg ? chall->alg->name : \"[unknown]\");\n\t} else if (ne_strcasecmp(key, \"qop\") == 0) {\n            /* iterate over each token in the value */\n            do {\n                const char *tok = ne_shave(ne_token(&val, ','), \" \\t\");\n                \n                if (ne_strcasecmp(tok, \"auth\") == 0) {\n                    chall->qop_auth = 1;\n                }\n            } while (val);\n            \n            chall->got_qop = chall->qop_auth;\n\t}\n        else if (ne_strcasecmp(key, \"domain\") == 0) {\n            chall->domain = val;\n        }\n        else if (ne_strcasecmp(key, \"userhash\") == 0) {\n            if (strcmp(val, \"true\") == 0)\n                chall->userhash = userhash_true;\n            else if (strcmp(val, \"false\") == 0)\n                chall->userhash = userhash_false;\n            else\n                NE_DEBUG(NE_DBG_HTTPAUTH, \"auth: Ignored bogus userhash value '%s'\\n\", val);\n        }\n    }\n\n    /* Insert the in-flight challenge (if any). */\n    if (chall) insert_challenge(&challenges, chall);\n    \n    sess->protocol = NULL;\n\n    /* Iterate through the challenge list (which is sorted from\n     * strongest to weakest) attempting to accept each one. */\n    for (chall = challenges; chall != NULL; chall = chall->next) {\n        NE_DEBUG(NE_DBG_HTTPAUTH, \"auth: Trying %s challenge...\\n\",\n                 chall->protocol->name);\n        if (chall->protocol->challenge(sess, attempt, chall, uri, &errmsg) == 0) {\n            NE_DEBUG(NE_DBG_HTTPAUTH, \"auth: Accepted %s challenge.\\n\", \n                     chall->protocol->name);\n            sess->protocol = chall->protocol;\n            break;\n        }\n    }\n\n    if (!sess->protocol) {\n        NE_DEBUG(NE_DBG_HTTPAUTH, \"auth: No challenges accepted.\\n\");\n        ne_set_error(sess->sess, _(sess->spec->error_noauth),\n                     errmsg ? errmsg->data : _(\"could not parse challenge\"));\n    }\n\n    while (challenges != NULL) {\n\tchall = challenges->next;\n\tne_free(challenges);\n\tchallenges = chall;\n    }\n\n    ne_free(hdr);\n    if (errmsg) ne_buffer_destroy(errmsg);\n\n    return !(sess->protocol != NULL);\n}\n\nstatic void ah_create(ne_request *req, void *session, const char *method,\n\t\t      const char *target)\n{\n    auth_session *sess = session;\n    int is_connect = strcmp(method, \"CONNECT\") == 0;\n\n    if (sess->context == AUTH_ANY ||\n        (is_connect && sess->context == AUTH_CONNECT) ||\n        (!is_connect && sess->context == AUTH_NOTCONNECT)) {\n        struct auth_request *areq = ne_calloc(sizeof *areq);\n        struct auth_handler *hdl;\n        \n        NE_DEBUG(NE_DBG_HTTPAUTH, \"auth: Create for %s\\n\", sess->spec->resp_hdr);\n        \n        areq->method = method;\n        areq->target = target;\n        areq->request = req;\n        \n        ne_set_request_private(req, sess->spec->id, areq);\n\n        /* For each new request, reset the attempt counter in every\n         * registered handler. */\n        for (hdl = sess->handlers; hdl; hdl = hdl->next) {\n            hdl->attempt = 0;\n        }\n    }\n}\n\n\nstatic void ah_pre_send(ne_request *r, void *cookie, ne_buffer *request)\n{\n    auth_session *sess = cookie;\n    struct auth_request *req = ne_get_request_private(r, sess->spec->id);\n\n    if (sess->protocol && req) {\n\tchar *value;\n\n        NE_DEBUG(NE_DBG_HTTPAUTH, \"auth: Sending '%s' response.\\n\",\n                 sess->protocol->name);\n\n        value = sess->protocol->response(sess, req);\n\n\tif (value != NULL) {\n\t    ne_buffer_concat(request, sess->spec->req_hdr, \": \", value, NULL);\n\t    ne_free(value);\n\t}\n    }\n\n}\n\nstatic int ah_post_send(ne_request *req, void *cookie, const ne_status *status)\n{\n    auth_session *sess = cookie;\n    struct auth_request *areq = ne_get_request_private(req, sess->spec->id);\n    const char *auth_hdr, *auth_info_hdr;\n    int ret = NE_OK;\n\n    if (!areq) return NE_OK;\n\n    auth_hdr = ne_get_response_header(req, sess->spec->resp_hdr);\n    auth_info_hdr = ne_get_response_trailer(req, sess->spec->resp_info_hdr);\n    if (!auth_info_hdr)\n        auth_info_hdr = ne_get_response_header(req, sess->spec->resp_info_hdr);\n\n    if (sess->context == AUTH_CONNECT && status->code == 401 && !auth_hdr) {\n        /* Some broken proxies issue a 401 as a proxy auth challenge\n         * to a CONNECT request; handle this here. */\n        auth_hdr = ne_get_response_header(req, \"WWW-Authenticate\");\n        auth_info_hdr = NULL;\n    }\n\n#ifdef HAVE_GSSAPI\n    /* whatever happens: forget the GSSAPI token cached thus far */\n    if (sess->gssapi_token) {\n        ne_free(sess->gssapi_token);\n        sess->gssapi_token = NULL;\n    }\n#endif\n\n#ifdef HAVE_SSPI\n    /* whatever happens: forget the SSPI token cached thus far */\n    if (sess->sspi_token) {\n        ne_free(sess->sspi_token);\n        sess->sspi_token = NULL;\n    }\n#endif\n\n    NE_DEBUG(NE_DBG_HTTPAUTH, \n\t     \"auth: Post-send (#%d), code is %d (want %d), %s is %s\\n\",\n\t     areq->attempt, status->code, sess->spec->status_code, \n\t     sess->spec->resp_hdr, auth_hdr ? auth_hdr : \"(none)\");\n    if (auth_info_hdr && sess->protocol && sess->protocol->verify \n        && (sess->protocol->flags & AUTH_FLAG_VERIFY_NON40x) == 0) {\n        ret = sess->protocol->verify(areq, sess, auth_info_hdr);\n    }\n    else if (sess->protocol && sess->protocol->verify\n             && (sess->protocol->flags & AUTH_FLAG_VERIFY_NON40x) \n             && (status->klass == 2 || status->klass == 3)\n             && auth_hdr) {\n        ret = sess->protocol->verify(areq, sess, auth_hdr);\n    }\n    else if ((status->code == sess->spec->status_code ||\n              (status->code == 401 && sess->context == AUTH_CONNECT)) &&\n\t       auth_hdr) {\n        /* note above: allow a 401 in response to a CONNECT request\n         * from a proxy since some buggy proxies send that. */\n\tNE_DEBUG(NE_DBG_HTTPAUTH, \"auth: Got challenge (code %d).\\n\", status->code);\n\tif (!auth_challenge(sess, areq->attempt++, areq->target, auth_hdr)) {\n\t    ret = NE_RETRY;\n\t} else {\n\t    clean_session(sess);\n\t    ret = sess->spec->fail_code;\n\t}\n        \n        /* Set or clear the conn-auth flag according to whether this\n         * was an accepted challenge for a borked protocol. */\n        ne_set_session_flag(sess->sess, NE_SESSFLAG_CONNAUTH,\n                            sess->protocol \n                            && (sess->protocol->flags & AUTH_FLAG_CONN_AUTH));\n    }\n\n#ifdef HAVE_SSPI\n    /* Clear the SSPI context after successful authentication. */\n    if (status->code != sess->spec->status_code && sess->sspi_context) {\n        ne_sspi_clear_context(sess->sspi_context);\n    }\n#endif\n\n    return ret;\n}\n\nstatic void ah_destroy(ne_request *req, void *session)\n{\n    auth_session *sess = session;\n    struct auth_request *areq = ne_get_request_private(req, sess->spec->id);\n\n    if (areq) {\n        ne_free(areq);\n    }\n}\n\nstatic void free_auth(void *cookie)\n{\n    auth_session *sess = cookie;\n    struct auth_handler *hdl, *next;\n\n#ifdef HAVE_GSSAPI\n    if (sess->gssname != GSS_C_NO_NAME) {\n        unsigned int major;\n        gss_release_name(&major, &sess->gssname);\n    }\n#endif\n\n    for (hdl = sess->handlers; hdl; hdl = next) {\n        next = hdl->next;\n        ne_free(hdl);\n    }\n\n    clean_session(sess);\n#ifdef HAVE_SSPI\n    if (sess->sspi_host) ne_free(sess->sspi_host);\n    sess->sspi_host = NULL;\n#endif\n    ne_free(sess);\n}\n\nstatic void auth_register(ne_session *sess, int isproxy, unsigned protomask,\n                          const struct auth_class *ahc, const char *id,\n                          ne_auth_creds old_creds, ne_auth_provide new_creds,\n                          void *userdata)\n{\n    auth_session *ahs;\n    struct auth_handler **hdl;\n\n    /* Handle the _ALL and _DEFAULT protocol masks: */\n    if ((protomask & NE_AUTH_ALL) == NE_AUTH_ALL) {\n        protomask |= NE_AUTH_BASIC | NE_AUTH_DIGEST | NE_AUTH_NEGOTIATE;\n    }\n    else if ((protomask & NE_AUTH_DEFAULT) == NE_AUTH_DEFAULT) {\n        protomask |= NE_AUTH_BASIC | NE_AUTH_DIGEST;\n        \n        if (strcmp(ne_get_scheme(sess), \"https\") == 0 || isproxy) {\n            protomask |= NE_AUTH_NEGOTIATE;\n        }\n    }\n\n    /* For backwards-compatibility with older releases where DIGEST\n     * used to be defined as WEAKEST, if only LEGACY_DIGEST is given,\n     * that implies DIGEST|LEGACY_DIGEST. */\n    if ((protomask & (NE_AUTH_LEGACY_DIGEST|NE_AUTH_DIGEST)) == NE_AUTH_LEGACY_DIGEST) {\n        NE_DEBUG(NE_DBG_HTTPAUTH, \"auth: Legacy Digest support compatibility mode.\\n\");\n        protomask |= NE_AUTH_DIGEST;\n    }\n\n    if ((protomask & NE_AUTH_NEGOTIATE) == NE_AUTH_NEGOTIATE) {\n        /* Map NEGOTIATE to NTLM | GSSAPI. */\n        protomask |= NE_AUTH_GSSAPI | NE_AUTH_NTLM;\n    }\n    \n    if ((protomask & NE_AUTH_GSSAPI) == NE_AUTH_GSSAPI) {\n        /* Map GSSAPI to GSSAPI_ONLY | SSPI. */\n        protomask |= NE_AUTH_GSSAPI_ONLY | NE_AUTH_SSPI;\n    }\n\n    ahs = ne_get_session_private(sess, id);\n    if (ahs == NULL) {\n        ahs = ne_calloc(sizeof *ahs);\n        \n        ahs->sess = sess;\n        ahs->spec = ahc;\n        \n        if (strcmp(ne_get_scheme(sess), \"https\") == 0) {\n            ahs->context = isproxy ? AUTH_CONNECT : AUTH_NOTCONNECT;\n        } else {\n            ahs->context = AUTH_ANY;\n        }\n        \n        /* Register hooks */\n        ne_hook_create_request(sess, ah_create, ahs);\n        ne_hook_pre_send(sess, ah_pre_send, ahs);\n        ne_hook_post_send(sess, ah_post_send, ahs);\n        ne_hook_destroy_request(sess, ah_destroy, ahs);\n        ne_hook_destroy_session(sess, free_auth, ahs);\n        \n        ne_set_session_private(sess, id, ahs);\n    }\n\n#ifdef HAVE_GSSAPI\n    if ((protomask & NE_AUTH_GSSAPI_ONLY) && ahs->gssname == GSS_C_NO_NAME) {\n        ne_uri uri = {0};\n        \n        if (isproxy)\n            ne_fill_proxy_uri(sess, &uri);\n        else\n            ne_fill_server_uri(sess, &uri);\n\n        get_gss_name(&ahs->gssname, uri.host);\n\n        ne_uri_free(&uri);\n    }\n#endif\n#ifdef HAVE_SSPI\n    if ((protomask & (NE_AUTH_NTLM|NE_AUTH_SSPI)) && !ahs->sspi_host) {\n        ne_uri uri = {0};\n        \n        if (isproxy)\n            ne_fill_proxy_uri(sess, &uri);\n        else\n            ne_fill_server_uri(sess, &uri);\n\n        ahs->sspi_host = uri.host;\n        uri.host = NULL;\n\n        ne_uri_free(&uri);\n    }\n#endif        \n\n    /* Find the end of the handler list, and add a new one. */\n    hdl = &ahs->handlers;\n    while (*hdl)\n        hdl = &(*hdl)->next;\n        \n    *hdl = ne_malloc(sizeof **hdl);\n    (*hdl)->protomask = protomask;\n    (*hdl)->old_creds = old_creds;\n    (*hdl)->new_creds = new_creds;\n    (*hdl)->userdata = userdata;\n    (*hdl)->next = NULL;\n    (*hdl)->attempt = 0;\n}\n\nvoid ne_set_server_auth(ne_session *sess, ne_auth_creds creds, void *userdata)\n{\n    auth_register(sess, 0, NE_AUTH_DEFAULT, &ah_server_class, HOOK_SERVER_ID,\n                  creds, NULL, userdata);\n}\n\nvoid ne_set_proxy_auth(ne_session *sess, ne_auth_creds creds, void *userdata)\n{\n    auth_register(sess, 1, NE_AUTH_DEFAULT, &ah_proxy_class, HOOK_PROXY_ID,\n                  creds, NULL, userdata);\n}\n\nvoid ne_add_server_auth(ne_session *sess, unsigned protocol, \n                        ne_auth_creds creds, void *userdata)\n{\n    auth_register(sess, 0, protocol, &ah_server_class, HOOK_SERVER_ID,\n                  creds, NULL, userdata);\n}\n\nvoid ne_add_proxy_auth(ne_session *sess, unsigned protocol, \n                       ne_auth_creds creds, void *userdata)\n{\n    auth_register(sess, 1, protocol, &ah_proxy_class, HOOK_PROXY_ID,\n                  creds, NULL, userdata);\n}\n\nvoid ne_add_auth(ne_session *sess, unsigned protocol,\n                 ne_auth_provide new_creds, void *userdata)\n{\n    auth_register(sess, 0, protocol, &ah_proxy_class, HOOK_PROXY_ID,\n                  NULL, new_creds, userdata);\n    auth_register(sess, 0, protocol, &ah_server_class, HOOK_SERVER_ID,\n                  NULL, new_creds, userdata);\n}\n\nvoid ne_forget_auth(ne_session *sess)\n{\n    auth_session *as;\n    if ((as = ne_get_session_private(sess, HOOK_SERVER_ID)) != NULL)\n\tclean_session(as);\n    if ((as = ne_get_session_private(sess, HOOK_PROXY_ID)) != NULL)\n\tclean_session(as);\n}\n\n"
  },
  {
    "path": "src/ne_auth.h",
    "content": "/* \n   HTTP authentication routines\n   Copyright (C) 1999-2021, Joe Orton <joe@manyfish.co.uk>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n   \n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n\n#ifndef NE_AUTH_H\n#define NE_AUTH_H\n\n#include \"ne_session.h\" /* for ne_session */\n\nNE_BEGIN_DECLS\n\n/* Size of username/password buffers passed to ne_auth_creds\n * callback. */\n#define NE_ABUFSIZ (256)\n\n/* The callback used to request the username and password in the given\n * realm. The username and password must be copied into the buffers\n * which are both of size NE_ABUFSIZ.  The 'attempt' parameter is zero\n * on the first call to the callback, and increases by one for each\n * invocation of the callback during an attempt to authenticate.  The\n * 'realm' parameter is provided by the server, the string is cleaned\n * of non-printable characters.\n *\n * The callback must return zero to indicate that authentication\n * should be attempted with the username/password, or non-zero to\n * cancel the request. (if non-zero, username and password are\n * ignored.)\n *\n * IMPORTANT NOTE: The callback will be invoked repeatedly until\n * either it returns non-zero, or authentication is successful.\n *\n * Hint: if you just wish to attempt authentication just once (even if\n * the user gets the username/password wrong), have the callback\n * function use 'attempt' value as the function return value. */\ntypedef int (*ne_auth_creds)(void *userdata, const char *realm, int attempt,\n\t\t\t     char *username, char *password);\n\n/* Set callbacks to provide credentials for server and proxy\n * authentication, using the default set of authentication protocols.\n * userdata is passed as the first argument to the callback. */\nvoid ne_set_server_auth(ne_session *sess, ne_auth_creds creds, void *userdata);\nvoid ne_set_proxy_auth(ne_session *sess, ne_auth_creds creds, void *userdata);\n\n/* As an alternative to using ne_set_server_auth and\n * ne_set_proxy_auth, the following interfaces may be used; these\n * allow control over which authentication protocol is used. */\n\n/* NE_AUTH_BASIC: Basic authentication transmits the username and\n * password unprotected over the channel; this allows a passive attack\n * to steal the credentials if using an unsecured channel\n * (i.e. non-SSL). */\n#define NE_AUTH_BASIC (0x0001)\n\n/* NE_AUTH_DIGEST: Digest authentication uses a hash of the username,\n * password, and certain aspects of the request, so prevents passive\n * attackers from obtaining the credentials; active attackers can\n * still modify most of the request/response if using an unsecured\n * channel.  Supports algorithms from RFC 2617 and RFC 7616. */\n#define NE_AUTH_DIGEST (0x0080)\n\n/* NE_AUTH_LEGACY_DIGEST: Using this flag together with NE_AUTH_DIGEST\n * enables support for the weaker, legacy version of the Digest\n * algorithm specified in RFC 2069 (obsoleted by RFC 2617, which was\n * published in June 1999).  */\n#define NE_AUTH_LEGACY_DIGEST (0x0002)\n\n/* NE_AUTH_NEGOTIATE: Negotiate uses GSSAPI/SSPI, or NTLM, to\n * authenticate the user; an active attacker can modify any of the\n * request/response at will, so this must not be used over an\n * unsecured channel.  NE_AUTH_NEGOTIATE is currently equivalent to\n * use of (NE_AUTH_GSSAPI | NE_AUTH_NTLM). */\n#define NE_AUTH_NEGOTIATE (0x0004)\n\n/* NE_AUTH_GSSAPI: Use GSSAPI or SSPI to authenticate the user; an\n * active attacker can modify any of the request/response at will, so\n * this must not be used over an unsecured channel. NE_AUTH_GSSAPI\n * is currently equivalent to (NE_AUTH_GSSAPI_ONLY | NE_AUTH_SSPI). */\n#define NE_AUTH_GSSAPI (0x0008)\n\n/* NE_AUTH_NTLM: Use NTLM to authenticate the user; an active attacker\n * can modify any of the request/response at will, so this must not be\n * used over an unsecured channel. */\n#define NE_AUTH_NTLM (0x0010)\n\n/* NE_AUTH_SSPI: Use SSPI to authenticate the user; an\n * active attacker can modify any of the request/response at will, so\n * this must not be used over an unsecured channel. */\n#define NE_AUTH_SSPI (0x0020)\n\n/* NE_AUTH_GSSAPI_ONLY: Use GSSAPI to authenticate the user; an\n * active attacker can modify any of the request/response at will, so\n * this must not be used over an unsecured channel. */\n#define NE_AUTH_GSSAPI_ONLY (0x0040)\n\n/* 0x0080: legacy definition of NE_AUTH_DIGEST in 0.31 and earlier */\n\n/* The default set of supported protocols, as deemed appropriate for\n * the given session scheme.  The interpretation of this flag may\n * change across versions, for example with older, less secure\n * protocols being removed from the default set. */\n#define NE_AUTH_DEFAULT (0x1000)\n\n/* All protocols supported by the library. The interpretation of this\n * flag may change across versions. */\n#define NE_AUTH_ALL (0x2000)\n\n/* If present in the protocol mask passed to ne_auth_provide,\n * indicates that proxy authentication is requested. */\n#define NE_AUTH_PROXY (0x4000)\n\n/* Add a callback to provide credentials for server and proxy\n * authentication using a particular auth protocol or set of\n * protocols.  The protocol is supplied as a bitmask of NE_AUTH_*\n * values.  For NE_AUTH_NEGOTIATE, the creds and userdata arguments\n * are ignored and may be NULL.\n *\n * These functions may be called multiple times per session to\n * register callbacks for different protocols.  If the server presents\n * more than one protocol in an auth challenge, the following\n * algorithm will be used to determine which callback is used:\n *\n * - iterate over the registered callbacks in the order registered\n * - for each each callback, iterate over the known set of protocols\n *   in order of algorithm strength (strongest first).\n * - if the protocol mask for that callback matches the protocol,\n *   attempt authentication using this protocol.\n *\n * Therefore, if multiple calls to ne_add_server_auth or\n * ne_add_proxy_auth are used for a given session, the caller must\n * ensure that the order in which those calls are made reflects the\n * precedence of protocols to be used. */\nvoid ne_add_server_auth(ne_session *sess, unsigned protocol, \n                        ne_auth_creds creds, void *userdata);\nvoid ne_add_proxy_auth(ne_session *sess, unsigned protocol, \n                       ne_auth_creds creds, void *userdata);\n\n/* Alternative credentials provider callback, invoked when credentials\n * are required to authenticate the client to either a server or\n * proxy.  'protocol' is the authentication protocol number\n * (NE_AUTH_*) of the challenge, bitwise-ORed with NE_AUTH_PROXY when\n * the auth challenge is made by an HTTP proxy.\n *\n * 'realm' is the realm name provided by the server, and is cleaned of\n * non-printable characters.  The 'attempt' counter reflects the\n * number of attempts to provide credentials to the server\n * (i.e. retried requests sent with a challenge response), NOT the\n * number of times the callback is invoked, unlike the ne_auth_creds\n * callback.\n *\n * The callback must return zero to indicate that authentication\n * should be attempted with the username/password, or non-zero to\n * cancel the request. (if non-zero, username and password are\n * ignored.)\n *\n * The username and password buffers have length 'buflen', which is\n * guaranteed to be >= NE_ABUFSIZ.  The username must be provided as a\n * NUL-terminated UTF-8 encoding only.  The password must be provided\n * as a NUL-terminated string.  Additional protocol-specific\n * restrictions apply, e.g. username cannot contain a colon for Basic\n * auth.\n *\n * IMPORTANT NOTE: The callback will be invoked repeatedly until\n * either it returns non-zero, or authentication is successful.\n *\n * Hint: if you just wish to attempt authentication just once (even if\n * the user gets the username/password wrong), have the callback\n * function use 'attempt' value as the function return value. */\ntypedef int (*ne_auth_provide)(void *userdata, int attempt,\n                               unsigned protocol, const char *realm,\n                               char *username, char *password, size_t buflen);\n\nvoid ne_add_auth(ne_session *sess, unsigned protocol,\n                 ne_auth_provide creds, void *userdata);\n\n/* Clear any cached authentication credentials for the given\n * session. */\nvoid ne_forget_auth(ne_session *sess);\n\nNE_END_DECLS\n\n#endif /* NE_AUTH_H */\n"
  },
  {
    "path": "src/ne_basic.c",
    "content": "/* \n   Basic HTTP and WebDAV methods\n   Copyright (C) 1999-2021, Joe Orton <joe@manyfish.co.uk>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n   \n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n\n#include \"config.h\"\n\n#include <sys/types.h>\n#include <sys/stat.h> /* for struct stat */\n\n#ifdef HAVE_STRING_H\n#include <string.h>\n#endif\n#ifdef HAVE_UNISTD_H\n#include <unistd.h>\n#endif\n#ifdef HAVE_STDLIB_H\n#include <stdlib.h>\n#endif\n\n#include <errno.h>\n\n#include \"ne_request.h\"\n#include \"ne_alloc.h\"\n#include \"ne_utils.h\"\n#include \"ne_basic.h\"\n#include \"ne_207.h\"\n\n#ifdef NE_HAVE_DAV\n#include \"ne_uri.h\"\n#include \"ne_locks.h\"\n#endif\n\n#include \"ne_dates.h\"\n#include \"ne_internal.h\"\n\nint ne_getmodtime(ne_session *sess, const char *path, time_t *modtime)\n{\n    ne_request *req = ne_request_create(sess, \"HEAD\", path);\n    const char *value;\n    int ret;\n\n    ret = ne_request_dispatch(req);\n\n    value = ne_get_response_header(req, \"Last-Modified\"); \n\n    if (ret == NE_OK && ne_get_status(req)->klass != 2) {\n\t*modtime = -1;\n\tret = NE_ERROR;\n    } \n    else if (value) {\n        *modtime = ne_httpdate_parse(value);\n    }\n    else {\n        *modtime = -1;\n    }\n\n    ne_request_destroy(req);\n\n    return ret;\n}\n\n#ifdef NE_LFS\n#define ne_fstat fstat64\ntypedef struct stat64 struct_stat;\n#else\n#define ne_fstat fstat\ntypedef struct stat struct_stat;\n#endif\n\n/* PUT's from fd to PATH */\nint ne_put(ne_session *sess, const char *path, int fd)\n{\n    ne_request *req;\n    struct_stat st;\n    int ret;\n\n    if (ne_fstat(fd, &st)) {\n        int errnum = errno;\n        char buf[200];\n\n        ne_set_error(sess, _(\"Could not determine file size: %s\"),\n                     ne_strerror(errnum, buf, sizeof buf));\n        return NE_ERROR;\n    }\n    \n    req = ne_request_create(sess, \"PUT\", path);\n\n#ifdef NE_HAVE_DAV\n    ne_lock_using_resource(req, path, 0);\n    ne_lock_using_parent(req, path);\n#endif\n\n    ne_set_request_body_fd(req, fd, 0, st.st_size);\n\t\n    ret = ne_request_dispatch(req);\n    \n    if (ret == NE_OK && ne_get_status(req)->klass != 2)\n\tret = NE_ERROR;\n\n    ne_request_destroy(req);\n\n    return ret;\n}\n\nint ne_putbuf(ne_session *sess, const char *path,\n              const char *buf, size_t buflen)\n{\n    ne_request *req = ne_request_create(sess, \"PUT\", path);\n    int ret;\n\n#ifdef NE_HAVE_DAV\n    ne_lock_using_resource(req, path, 0);\n    ne_lock_using_parent(req, path);\n#endif\n\n    ne_set_request_body_buffer(req, buf, buflen);\n\n    ret = ne_request_dispatch(req);\n\n    if (ret == NE_OK && ne_get_status(req)->klass != 2)\n\tret = NE_ERROR;\n\n    ne_request_destroy(req);\n\n    return ret;\n}\n\nint ne_getbuf(ne_session *sess, const char *path,\n              char *buf, size_t *buflen)\n{\n    ne_request *req = ne_request_create(sess, \"GET\", path);\n    int ret, is_2xx;\n\n    do {\n        ret = ne_begin_request(req);\n        if (ret != NE_OK) break;\n\n        is_2xx = ne_get_status(req)->klass == 2;\n        if (is_2xx)\n            ret = ne_read_response_to_buffer(req, buf, buflen);\n        else\n            ret = ne_discard_response(req);\n\n        if (ret == NE_OK) ret = ne_end_request(req);\n    } while (ret == NE_RETRY);\n\n    if (ret != NE_OK)\n        ne_close_connection(sess);\n    else if (!is_2xx)\n        ret = NE_ERROR;\n\n    ne_request_destroy(req);\n\n    return ret;\n}\n\n/* Dispatch a GET request REQ, writing the response body to FD fd.  If\n * RANGE is non-NULL, then it is the value of the Range request\n * header, e.g. \"bytes=1-5\".  Returns an NE_* error code. */\nstatic int dispatch_to_fd(ne_request *req, int fd, const char *range)\n{\n    ne_session *const sess = ne_get_session(req);\n    const ne_status *const st = ne_get_status(req);\n    int ret;\n    size_t rlen;\n\n    /* length of bytespec after \"bytes=\" */\n    rlen = range ? strlen(range + 6) : 0;\n\n    do {\n        const char *value;\n        \n        ret = ne_begin_request(req);\n        if (ret != NE_OK) break;\n\n        value = ne_get_response_header(req, \"Content-Range\");\n\n        /* For a 206 response, check that a Content-Range header is\n         * given which matches the Range request header. */\n        if (range && st->code == 206 \n            && (value == NULL || strncmp(value, \"bytes \", 6) != 0\n                || strncmp(range + 6, value + 6, rlen)\n                || (range[5 + rlen] != '-' && value[6 + rlen] != '/'))) {\n            ne_set_error(sess, _(\"Response did not include requested range\"));\n            return NE_ERROR;\n        }\n\n        if ((range && st->code == 206) || (!range && st->klass == 2)) {\n            ret = ne_read_response_to_fd(req, fd);\n        }\n        else {\n            ret = ne_discard_response(req);\n        }\n\n        if (ret == NE_OK) ret = ne_end_request(req);\n    } while (ret == NE_RETRY);\n\n    return ret;\n}\n\nstatic int get_range_common(ne_session *sess, const char *path,\n                            const char *brange, int fd)\n\n{\n    ne_request *req = ne_request_create(sess, \"GET\", path);\n    const ne_status *status;\n    int ret;\n\n    ne_add_request_header(req, \"Range\", brange);\n    ne_add_request_header(req, \"Accept-Ranges\", \"bytes\");\n\n    ret = dispatch_to_fd(req, fd, brange);\n\n    status = ne_get_status(req);\n\n    if (ret == NE_OK && status->code == 416) {\n\t/* connection is terminated too early with Apache/1.3, so we check\n\t * this even if ret == NE_ERROR... */\n\tne_set_error(sess, _(\"Range is not satisfiable\"));\n\tret = NE_ERROR;\n    }\n    else if (ret == NE_OK) {\n\tif (status->klass == 2 && status->code != 206) {\n\t    ne_set_error(sess, _(\"Resource does not support ranged GET requests\"));\n\t    ret = NE_ERROR;\n\t}\n\telse if (status->klass != 2) {\n\t    ret = NE_ERROR;\n\t}\n    } \n    \n    ne_request_destroy(req);\n\n    return ret;\n}\n\nint ne_get_range(ne_session *sess, const char *path,\n\t\t ne_content_range *range, int fd)\n{\n    char brange[64];\n\n    if (range->end == -1) {\n        ne_snprintf(brange, sizeof brange, \"bytes=%\" FMT_NE_OFF_T \"-\",\n                    range->start);\n    }\n    else {\n\tne_snprintf(brange, sizeof brange,\n                    \"bytes=%\" FMT_NE_OFF_T \"-%\" FMT_NE_OFF_T,\n                    range->start, range->end);\n    }\n\n    return get_range_common(sess, path, brange, fd);\n}\n\n/* Get to given fd */\nint ne_get(ne_session *sess, const char *path, int fd)\n{\n    ne_request *req = ne_request_create(sess, \"GET\", path);\n    int ret;\n\n    ret = dispatch_to_fd(req, fd, NULL);\n    \n    if (ret == NE_OK && ne_get_status(req)->klass != 2) {\n\tret = NE_ERROR;\n    }\n\n    ne_request_destroy(req);\n\n    return ret;\n}\n\n\n/* Get to given fd */\nint ne_post(ne_session *sess, const char *path, int fd, const char *buffer)\n{\n    ne_request *req = ne_request_create(sess, \"POST\", path);\n    int ret;\n\n    ne_set_request_flag(req, NE_REQFLAG_IDEMPOTENT, 0);\n\n    ne_set_request_body_buffer(req, buffer, strlen(buffer));\n\n    ret = dispatch_to_fd(req, fd, NULL);\n    \n    if (ret == NE_OK && ne_get_status(req)->klass != 2) {\n\tret = NE_ERROR;\n    }\n\n    ne_request_destroy(req);\n\n    return ret;\n}\n\nint ne_get_content_type(ne_request *req, ne_content_type *ct)\n{\n    const char *value;\n    char *sep, *stype;\n\n    value = ne_get_response_header(req, \"Content-Type\");\n    if (value == NULL || strchr(value, '/') == NULL) {\n        return -1;\n    }\n\n    ct->value = ne_strdup(value);\n    \n    stype = strchr(ct->value, '/');\n    *stype++ = '\\0';\n\n    ct->type = ne_strlower(ct->value);\n    ct->charset = NULL;\n    \n    sep = strchr(stype, ';');\n\n    if (sep) {\n\tchar *tok, *eq;\n\n        /* NUL-terminate at the ; and iterate through each parameter\n         * (each is ;-separated). Follow grammar at\n         * https://www.rfc-editor.org/rfc/rfc9110#parameter allowing\n         * for OWS */\n\t*sep++ = '\\0';\n\tdo {\n\t    tok = ne_qtoken(&sep, ';', \"\\\"\\'\");\n\t    if (tok && (eq = strchr(tok, '=')) != NULL) {\n                /* NUL-terminate to split parameter-name (tok) from\n                 * parameter-value (eq). */\n                *eq++ = '\\0';\n                if (ne_strcasecmp(ne_shave(tok, \" \"), \"charset\") == 0)\n\t\t    ct->charset = ne_shave(eq, \"\\\"\\' \");\n\t    }\n\t} while (sep && tok);\n    }\n\n    /* set subtype, losing any trailing whitespace */\n    ct->subtype = ne_strlower(ne_shave(stype, \" \\t\"));\n    \n    return 0;\n}\n\nstatic const struct options_map {\n    const char *name;\n    unsigned int cap;\n} options_map[] = {\n    { \"1\", NE_CAP_DAV_CLASS1 },\n    { \"2\", NE_CAP_DAV_CLASS2 },\n    { \"3\", NE_CAP_DAV_CLASS3 },\n    { \"<http://apache.org/dav/propset/fs/1>\", NE_CAP_MODDAV_EXEC },\n    { \"access-control\", NE_CAP_DAV_ACL },\n    { \"version-control\", NE_CAP_VER_CONTROL },\n    { \"checkout-in-place\", NE_CAP_CO_IN_PLACE },\n    { \"version-history\", NE_CAP_VER_HISTORY },\n    { \"workspace\", NE_CAP_WORKSPACE },\n    { \"update\", NE_CAP_UPDATE },\n    { \"label\", NE_CAP_LABEL },\n    { \"working-resource\", NE_CAP_WORK_RESOURCE },\n    { \"merge\", NE_CAP_MERGE },\n    { \"baseline\", NE_CAP_BASELINE },\n    { \"version-controlled-collection\", NE_CAP_VC_COLLECTION },\n    { \"extended-mkcol\", NE_CAP_EXT_MKCOL }\n};\n\nstatic void parse_dav_header(const char *value, unsigned int *caps)\n{\n    char *tokens = ne_strdup(value), *pnt = tokens;\n    \n    *caps = 0;\n\n    do {\n        char *tok = ne_qtoken(&pnt, ',',  \"\\\"'\");\n        unsigned n;\n\n        if (!tok) break;\n        \n        tok = ne_shave(tok, \" \\r\\t\\n\");\n\n        for (n = 0; n < sizeof(options_map)/sizeof(options_map[0]); n++) {\n            if (strcmp(tok, options_map[n].name) == 0) {\n                *caps |= options_map[n].cap;\n            }\n        }\n    } while (pnt != NULL);\n    \n    ne_free(tokens);\n}\n\nint ne_options2(ne_session *sess, const char *path, unsigned int *caps)\n{\n    ne_request *req = ne_request_create(sess, \"OPTIONS\", path);\n    int ret = ne_request_dispatch(req);\n    const char *header = ne_get_response_header(req, \"DAV\");\n    \n    if (header) parse_dav_header(header, caps);\n \n    if (ret == NE_OK && ne_get_status(req)->klass != 2) {\n\tret = NE_ERROR;\n    }\n    \n    ne_request_destroy(req);\n\n    return ret;\n}\n\nint ne_options(ne_session *sess, const char *path,\n               ne_server_capabilities *caps)\n{\n    int ret;\n    unsigned int capmask = 0;\n    \n    memset(caps, 0, sizeof *caps);\n\n    ret = ne_options2(sess, path, &capmask);\n\n    caps->dav_class1 = capmask & NE_CAP_DAV_CLASS1 ? 1 : 0;\n    caps->dav_class2 = capmask & NE_CAP_DAV_CLASS2 ? 1 : 0;\n    caps->dav_executable = capmask & NE_CAP_MODDAV_EXEC ? 1 : 0;\n    \n    return ret;\n}\n\n#ifdef NE_HAVE_DAV\n\nvoid ne_add_depth_header(ne_request *req, int depth)\n{\n    const char *value;\n    switch(depth) {\n    case NE_DEPTH_ZERO:\n\tvalue = \"0\";\n\tbreak;\n    case NE_DEPTH_ONE:\n\tvalue = \"1\";\n\tbreak;\n    default:\n\tvalue = \"infinity\";\n\tbreak;\n    }\n    ne_add_request_header(req, \"Depth\", value);\n}\n\nstatic int copy_or_move(ne_session *sess, int is_move, int overwrite,\n\t\t\tint depth, const char *src, const char *dest)\n{\n    ne_request *req = ne_request_create( sess, is_move?\"MOVE\":\"COPY\", src );\n\n    /* RFC4918§9.9.2 - \"Depth: infinity\" is implicit for MOVE. */\n    if (!is_move) {\n\tne_add_depth_header(req, depth);\n    }\n\n#ifdef NE_HAVE_DAV\n    if (is_move) {\n        /* Moving the resource requires any locks for the source\n         * resource (which may be a collection), and modifies the\n         * parent of the source. */\n        ne_lock_using_resource(req, src, NE_DEPTH_INFINITE);\n        ne_lock_using_parent(req, src);\n    }\n    ne_lock_using_resource(req, dest, NE_DEPTH_INFINITE);\n    /* And we need to be able to add members to the destination's parent */\n    ne_lock_using_parent(req, dest);\n#endif\n\n    if (ne_get_session_flag(sess, NE_SESSFLAG_RFC4918)) {\n        ne_add_request_header(req, \"Destination\", dest);\n    }\n    else {\n        ne_print_request_header(req, \"Destination\", \"%s://%s%s\",\n                                ne_get_scheme(sess),\n                                ne_get_server_hostport(sess), dest);\n    }\n    \n    ne_add_request_header(req, \"Overwrite\", overwrite?\"T\":\"F\");\n\n    return ne_simple_request(sess, req);\n}\n\nint ne_copy(ne_session *sess, int overwrite, int depth,\n\t     const char *src, const char *dest)\n{\n    return copy_or_move(sess, 0, overwrite, depth, src, dest);\n}\n\nint ne_move(ne_session *sess, int overwrite,\n\t     const char *src, const char *dest)\n{\n    return copy_or_move(sess, 1, overwrite, 0, src, dest);\n}\n\nint ne_delete(ne_session *sess, const char *path)\n{\n    ne_request *req = ne_request_create(sess, \"DELETE\", path);\n\n#ifdef NE_HAVE_DAV\n    ne_lock_using_resource(req, path, NE_DEPTH_INFINITE);\n    ne_lock_using_parent(req, path);\n#endif\n    \n    /* Per RFC4918§9.6.1 DELETE can get a 207 response. */\n    return ne_simple_request(sess, req);\n}\n\nint ne_mkcol(ne_session *sess, const char *path)\n{\n    ne_request *req;\n    char *real_path;\n    int ret;\n\n    if (ne_path_has_trailing_slash(path)) {\n\treal_path = ne_strdup(path);\n    }\n    else {\n\treal_path = ne_concat(path, \"/\", NULL);\n    }\n\n    req = ne_request_create(sess, \"MKCOL\", real_path);\n\n#ifdef NE_HAVE_DAV\n    ne_lock_using_resource(req, real_path, 0);\n    ne_lock_using_parent(req, real_path);\n#endif\n    \n    ret = ne_simple_request(sess, req);\n\n    ne_free(real_path);\n\n    return ret;\n}\n\n#endif /* NE_HAVE_DAV */\n"
  },
  {
    "path": "src/ne_basic.h",
    "content": "/* \n   HTTP/1.1 methods\n   Copyright (C) 1999-2021, Joe Orton <joe@manyfish.co.uk>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n   \n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n\n#ifndef NE_BASIC_H\n#define NE_BASIC_H\n\n#include <sys/types.h> /* for time_t */\n\n#include \"ne_request.h\"\n\nNE_BEGIN_DECLS\n\n/* Perform a GET request on resource at 'path', writing the entity\n * body which is returned to 'fd'. */\nint ne_get(ne_session *sess, const char *path, int fd);\n\n/* Perform a PUT request on resource at 'path', reading the entity\n * body to submit from 'fd'. */\nint ne_put(ne_session *sess, const char *path, int fd);\n\n/* Perform a PUT request on resource at 'path', including the entity\n * body 'buf' of length 'buflen'. */\nint ne_putbuf(ne_session *sess, const char *path,\n              const char *buf, size_t buflen);\n\n/* Perform a GET request on resource at 'path', for 2xx responses\n * writing the entity body which is returned to 'buffer', of maximum\n * length *buflen.  On return, *buflen is updated to reflect the\n * number of bytes received. If the response content length exceeds\n * the maximum, NE_FAILED is returned. */\nint ne_getbuf(ne_session *sess, const char *path,\n              char *buf, size_t *buflen);\n\n#define NE_DEPTH_ZERO (0)\n#define NE_DEPTH_ONE (1)\n#define NE_DEPTH_INFINITE (2)\n\n/* For ne_copy and ne_move:\n * \n * If a resource exists at \"dest\" and overwrite is zero, the operation\n * will fail; if overwrite is non-zero, any existing resource will\n * be over-written.\n */\n\n/* Copy resource from 'src to 'dest' paths. If 'src' identifies a\n * collection resource, depth may be NE_DEPTH_ZERO to request that the\n * collection and its properties are to be copied, or\n * NE_DEPTH_INFINITE to request that the collection and its contents\n * are to be copied.  Returns NE_* error code. */\nint ne_copy(ne_session *sess, int overwrite, int depth,\n\t    const char *src, const char *dest);\n\n/* Move resource from 'src' to 'dest' path.  Returns NE_* error\n * code. */\nint ne_move(ne_session *sess, int overwrite,\n\t    const char *src, const char *dest);\n\n/* Delete resource at 'path'.  Returns NE_* error code. */\nint ne_delete(ne_session *sess, const char *path);\n\n/* Create a collection at 'path', which is required to have a trailing\n * slash.  Returns NE_* error code. */\nint ne_mkcol(ne_session *sess, const char *path);\n\n/* Adds a Depth: header to a request. */\nvoid ne_add_depth_header(ne_request *req, int depth);\n\n/* Retrieve modification time of resource at location 'path', using\n * the HEAD method, placing parsed time in *modtime.  *modtime is set\n * to -1 if no Last-Modified response header was given, or the date\n * given could not be parsed.  Returns NE_* error code.  */\nint ne_getmodtime(ne_session *sess, const char *path, time_t *modtime);\n\ntypedef struct {\n    const char *type, *subtype;\n    const char *charset;\n    char *value;\n} ne_content_type;\n\n/* Retrieve the content-type of the response; returns zero if response\n * had valid content-type, in which case all fields in *ctype are set\n * (and never NULL); the caller must free(ctype->value) after use.\n * Returns non-zero on error, in which case *ctype is not altered. */\nint ne_get_content_type(ne_request *req, ne_content_type *ctype);\n\n/* DEPRECATED: Server capabilities. */\ntypedef struct {\n    unsigned int dav_class1; /* True if Class 1 WebDAV server */\n    unsigned int dav_class2; /* True if Class 2 WebDAV server */\n    unsigned int dav_executable; /* True if supports the 'executable'\n\t\t\t\t  * property a. la. mod_dav */\n} ne_server_capabilities;\n\n/* DEPRECATED: Determines server capabilities (using OPTIONS).  Use\n * ne_options2() instead. */\nint ne_options(ne_session *sess, const char *path,\n               ne_server_capabilities *caps);\n\n#define NE_CAP_DAV_CLASS1    (0x0001) /* Class 1 WebDAV (RFC 2518) */\n#define NE_CAP_DAV_CLASS2    (0x0002) /* Class 2 WebDAV (RFC 2518) */\n#define NE_CAP_DAV_CLASS3    (0x0004) /* Class 3 WebDAV (RFC 4918) */\n#define NE_CAP_MODDAV_EXEC   (0x0008) /* mod_dav \"executable\" property */\n#define NE_CAP_DAV_ACL       (0x0010) /* WebDAV ACL (RFC 3744) */\n#define NE_CAP_VER_CONTROL   (0x0020) /* DeltaV version-control */\n#define NE_CAP_CO_IN_PLACE   (0x0040) /* DeltaV checkout-in-place */\n#define NE_CAP_VER_HISTORY   (0x0080) /* DeltaV version-history */\n#define NE_CAP_WORKSPACE     (0x0100) /* DeltaV workspace */\n#define NE_CAP_UPDATE        (0x0200) /* DeltaV update */\n#define NE_CAP_LABEL         (0x0400) /* DeltaV label */\n#define NE_CAP_WORK_RESOURCE (0x0800) /* DeltaV working-resouce */\n#define NE_CAP_MERGE         (0x1000) /* DeltaV merge */\n#define NE_CAP_BASELINE      (0x2000) /* DeltaV baseline */\n#define NE_CAP_ACTIVITY      (0x4000) /* DeltaV activity */\n#define NE_CAP_VC_COLLECTION (0x8000) /* DeltaV version-controlled-collection */\n#define NE_CAP_EXT_MKCOL    (0x10000) /* extended-mkcol (RFC 5689) */\n\n/* Determines resource capailities, using an OPTIONS request.  On\n * return, *caps is set to a bit-mask of the above NE_CAP_* constants\n * describing the advertised resource capabilities. */\nint ne_options2(ne_session *sess, const char *path, unsigned int *caps);\n\n/* Defines a range of bytes, starting at 'start' and ending\n * at 'end'.  'total' is the number of bytes in the range.\n */\ntypedef struct {\n    ne_off_t start, end, total;\n} ne_content_range;\n\n/* Partial GET. range->start must be >= 0. range->total is ignored.\n *\n * If range->end is -1, then the rest of the resource from start is\n * requested, and range->total and end are filled in on success.\n *\n * Otherwise, bytes from range->start to range->end are requested.\n *\n * This will write to the CURRENT position of f; so if you want\n * to do a resume download, use:\n *      struct ne_content_range range;\n *      range.start = resume_from; \n *      range.end = range.start + 999;  (= 1000 bytes)\n *      fseek(myfile, resume_from, SEEK_SET);\n *      ne_get_range(sess, path, &range, myfile); */\nint ne_get_range(ne_session *sess, const char *path, \n\t\t ne_content_range *range, int fd);\n\n/* Post using buffer as request-body: stream response into f */\nint ne_post(ne_session *sess, const char *path, int fd, const char *buffer);\n\nNE_END_DECLS\n\n#endif /* NE_BASIC_H */\n"
  },
  {
    "path": "src/ne_compress.c",
    "content": "/* \n   Handling of compressed HTTP responses\n   Copyright (C) 2001-2021, Joe Orton <joe@manyfish.co.uk>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n   \n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n\n#include \"config.h\"\n\n#ifdef HAVE_STRING_H\n#include <string.h>\n#endif\n#ifdef HAVE_STDLIB_H\n#include <stdlib.h>\n#endif\n\n#include \"ne_request.h\"\n#include \"ne_compress.h\"\n#include \"ne_utils.h\"\n#include \"ne_internal.h\"\n\n#ifdef NE_HAVE_ZLIB\n\n#include <zlib.h>\n\n/* Adds support for the 'gzip' Content-Encoding in HTTP.  gzip is a\n * file format which wraps the DEFLATE compression algorithm.  zlib\n * implements DEFLATE: we have to unwrap the gzip format (specified in\n * RFC1952) as it comes off the wire, and hand off chunks of data to\n * be inflated. */\n\nstruct ne_decompress_s {\n    ne_request *request; /* associated request. */\n    ne_session *session; /* associated session. */\n    /* temporary buffer for holding inflated data. */\n    char outbuf[NE_BUFSIZ];\n    z_stream zstr;\n    int zstrinit; /* non-zero if zstr has been initialized */\n\n    /* pass blocks back to this. */\n    ne_block_reader reader;\n    ne_accept_response acceptor;\n    void *userdata;\n\n    /* buffer for gzip header bytes. */\n    unsigned char header[10];\n    size_t hdrcount;    /* bytes in header */\n\n    unsigned char footer[8];\n    size_t footcount; /* bytes in footer. */\n\n    /* CRC32 checksum: odd that zlib uses uLong for this since it is a\n     * 64-bit integer on LP64 platforms. */\n    uLong checksum;\n\n    /* current state. */\n    enum state {\n\tNE_Z_BEFORE_DATA, /* not received any response blocks yet. */\n\tNE_Z_PASSTHROUGH, /* response not compressed: passing through. */\n\tNE_Z_IN_HEADER, /* received a few bytes of response data, but not\n\t\t\t * got past the gzip header yet. */\n\tNE_Z_POST_HEADER, /* waiting for the end of the NUL-terminated bits. */\n\tNE_Z_INFLATING, /* inflating response bytes. */\n\tNE_Z_AFTER_DATA, /* after data; reading CRC32 & ISIZE */\n\tNE_Z_FINISHED /* stream is finished. */\n    } state;\n};\n\n/* Convert 'buf' to unsigned int; 'buf' must be 'unsigned char *' */\n#define BUF2UINT(buf) ((((unsigned int)(buf)[3])<<24) + ((buf)[2]<<16) + ((buf)[1]<<8) + (buf)[0])\n\n#define ID1 0x1f\n#define ID2 0x8b\n\n#define HDR_DONE 0\n#define HDR_EXTENDED 1\n#define HDR_ERROR 2\n\n#define HDR_ID1(ctx) ((ctx)->header[0])\n#define HDR_ID2(ctx) ((ctx)->header[1])\n#define HDR_CMETH(ctx) ((ctx)->header[2])\n#define HDR_FLAGS(ctx) ((ctx)->header[3])\n#define HDR_MTIME(ctx) (BUF2UINT(&(ctx)->header[4]))\n#define HDR_XFLAGS(ctx) ((ctx)->header[8])\n#define HDR_OS(ctx) ((ctx)->header[9])\n\n/* parse_header parses the gzip header, sets the next state and returns\n *   HDR_DONE: all done, bytes following are raw DEFLATE data.\n *   HDR_EXTENDED: all done, expect a NUL-termianted string\n *                 before the DEFLATE data\n *   HDR_ERROR: invalid header, give up (session error is set).\n */\nstatic int parse_header(ne_decompress *ctx)\n{\n    NE_DEBUG(NE_DBG_HTTP, \"ID1: %d  ID2: %d, cmeth %d, flags %d\\n\", \n             HDR_ID1(ctx), HDR_ID2(ctx), HDR_CMETH(ctx), HDR_FLAGS(ctx));\n    \n    if (HDR_ID1(ctx) != ID1 || HDR_ID2(ctx) != ID2 || HDR_CMETH(ctx) != 8) {\n\tne_set_error(ctx->session, \"Compressed stream invalid\");\n\treturn HDR_ERROR;\n    }\n\n    NE_DEBUG(NE_DBG_HTTP, \"mtime: %d, xflags: %d, os: %d\\n\",\n\t     HDR_MTIME(ctx), HDR_XFLAGS(ctx), HDR_OS(ctx));\n    \n    /* TODO: we can only handle one NUL-terminated extensions field\n     * currently.  Really, we should count the number of bits set, and\n     * skip as many fields as bits set (bailing if any reserved bits\n     * are set. */\n    if (HDR_FLAGS(ctx) == 8) {\n\tctx->state = NE_Z_POST_HEADER;\n\treturn HDR_EXTENDED;\n    } else if (HDR_FLAGS(ctx) != 0) {\n\tne_set_error(ctx->session, \"Compressed stream not supported\");\n\treturn HDR_ERROR;\n    }\n\n    NE_DEBUG(NE_DBG_HTTP, \"compress: Good stream.\\n\");\n    \n    ctx->state = NE_Z_INFLATING;\n    return HDR_DONE;\n}\n\n/* Process extra 'len' bytes of 'buf' which were received after the\n * DEFLATE data. */\nstatic int process_footer(ne_decompress *ctx, \n\t\t\t   const unsigned char *buf, size_t len)\n{\n    if (len + ctx->footcount > 8) {\n        ne_set_error(ctx->session, \n                     \"Too many bytes (%\" NE_FMT_SIZE_T \") in gzip footer\",\n                     len);\n        return -1;\n    } else {\n\tmemcpy(ctx->footer + ctx->footcount, buf, len);\n\tctx->footcount += len;\n\tif (ctx->footcount == 8) {\n\t    uLong crc = BUF2UINT(ctx->footer) & 0xFFFFFFFF;\n\t    if (crc == ctx->checksum) {\n\t\tctx->state = NE_Z_FINISHED;\n\t\tNE_DEBUG(NE_DBG_HTTP, \"compress: End of response; checksum match.\\n\");\n\t    } else {\n\t\tNE_DEBUG(NE_DBG_HTTP, \"compress: End of response; checksum mismatch: \"\n\t\t\t \"given %lu vs computed %lu\\n\", crc, ctx->checksum);\n\t\tne_set_error(ctx->session, \n\t\t\t     \"Checksum invalid for compressed stream\");\n                return -1;\n\t    }\n\t}\n    }\n    return 0;\n}\n\n/* A zlib function failed with 'code'; set the session error string\n * appropriately. */\nstatic void set_zlib_error(ne_decompress *ctx, const char *msg, int code)\n{\n    if (ctx->zstr.msg)\n        ne_set_error(ctx->session, \"%s: %s\", msg, ctx->zstr.msg);\n    else {\n        const char *err;\n        switch (code) {\n        case Z_STREAM_ERROR: err = \"stream error\"; break;\n        case Z_DATA_ERROR: err = \"data corrupt\"; break;\n        case Z_MEM_ERROR: err = \"out of memory\"; break;\n        case Z_BUF_ERROR: err = \"buffer error\"; break;\n        case Z_VERSION_ERROR: err = \"library version mismatch\"; break;\n        default: err = \"unknown error\"; break;\n        }\n        ne_set_error(ctx->session, _(\"%s: %s (code %d)\"), msg, err, code);\n    }\n}\n\n/* Inflate response buffer 'buf' of length 'len'. */\nstatic int do_inflate(ne_decompress *ctx, const char *buf, size_t len)\n{\n    int ret;\n\n    ctx->zstr.avail_in = len;\n    ctx->zstr.next_in = (unsigned char *)buf;\n    ctx->zstr.total_in = 0;\n    \n    do {\n\tctx->zstr.avail_out = sizeof ctx->outbuf;\n\tctx->zstr.next_out = (unsigned char *)ctx->outbuf;\n\tctx->zstr.total_out = 0;\n\t\n\tret = inflate(&ctx->zstr, Z_NO_FLUSH);\n\t\n\tNE_DEBUG(NE_DBG_HTTP, \n\t\t \"compress: inflate %d, %ld bytes out, %d remaining\\n\",\n\t\t ret, ctx->zstr.total_out, ctx->zstr.avail_in);\n#if 0\n\tNE_DEBUG(NE_DBG_HTTPBODY,\n\t\t \"Inflated body block (%ld):\\n[%.*s]\\n\", \n\t\t ctx->zstr.total_out, (int)ctx->zstr.total_out, \n\t\t ctx->outbuf);\n#endif\n\t/* update checksum. */\n\tctx->checksum = crc32(ctx->checksum, (unsigned char *)ctx->outbuf, \n\t\t\t      ctx->zstr.total_out);\n\n\t/* pass on the inflated data, if any */\n        if (ctx->zstr.total_out > 0) {\n            int rret = ctx->reader(ctx->userdata, ctx->outbuf,\n                                   ctx->zstr.total_out);\n            if (rret) return rret;\n        }\t\n    } while (ret == Z_OK && ctx->zstr.avail_in > 0);\n    \n    if (ret == Z_STREAM_END) {\n\tNE_DEBUG(NE_DBG_HTTP, \"compress: end of data stream, %d bytes remain.\\n\",\n\t\t ctx->zstr.avail_in);\n\t/* process the footer. */\n\tctx->state = NE_Z_AFTER_DATA;\n\treturn process_footer(ctx, ctx->zstr.next_in, ctx->zstr.avail_in);\n    } else if (ret != Z_OK) {\n        set_zlib_error(ctx, _(\"Could not inflate data\"), ret);\n        return NE_ERROR;\n    }\n    return 0;\n}\n\n/* Callback which is passed blocks of the response body. */\nstatic int gz_reader(void *ud, const char *buf, size_t len)\n{\n    ne_decompress *ctx = ud;\n    const char *zbuf;\n    size_t count;\n    const char *hdr;\n\n    if (len == 0) {\n        /* End of response: */\n        switch (ctx->state) {\n        case NE_Z_BEFORE_DATA:\n            hdr = ne_get_response_header(ctx->request, \"Content-Encoding\");\n            if (hdr && ne_strcasecmp(hdr, \"gzip\") == 0) {\n                /* response was truncated: return error. */\n                break;\n            }\n            /* else, fall through */\n        case NE_Z_FINISHED: /* complete gzip response */\n        case NE_Z_PASSTHROUGH: /* complete uncompressed response */\n            return ctx->reader(ctx->userdata, buf, 0);\n        default:\n            /* invalid state: truncated response. */\n            break;\n        }\n\t/* else: truncated response, fail. */\n\tne_set_error(ctx->session, \"Compressed response was truncated\");\n\treturn NE_ERROR;\n    }        \n\n    switch (ctx->state) {\n    case NE_Z_PASSTHROUGH:\n\t/* move along there. */\n\treturn ctx->reader(ctx->userdata, buf, len);\n\n    case NE_Z_FINISHED:\n\t/* Could argue for tolerance, and ignoring trailing content;\n\t * but it could mean something more serious. */\n\tif (len > 0) {\n\t    ne_set_error(ctx->session,\n\t\t\t \"Unexpected content received after compressed stream\");\n            return NE_ERROR;\n\t}\n        break;\n\n    case NE_Z_BEFORE_DATA:\n\t/* work out whether this is a compressed response or not. */\n        hdr = ne_get_response_header(ctx->request, \"Content-Encoding\");\n        if (hdr && ne_strcasecmp(hdr, \"gzip\") == 0) {\n            int ret;\n\t    NE_DEBUG(NE_DBG_HTTP, \"compress: got gzipped stream.\\n\");\n\n            /* inflateInit2() works here where inflateInit() doesn't. */\n            ret = inflateInit2(&ctx->zstr, -MAX_WBITS);\n            if (ret != Z_OK) {\n                set_zlib_error(ctx, _(\"Could not initialize zlib\"), ret);\n                return -1;\n            }\n\t    ctx->zstrinit = 1;\n\n\t} else {\n\t    /* No Content-Encoding header: pass it on.  TODO: we could\n\t     * hack it and register the real callback now. But that\n\t     * would require add_resp_body_rdr to have defined\n\t     * ordering semantics etc etc */\n\t    ctx->state = NE_Z_PASSTHROUGH;\n\t    return ctx->reader(ctx->userdata, buf, len);\n\t}\n\n\tctx->state = NE_Z_IN_HEADER;\n\t/* FALLTHROUGH */\n\n    case NE_Z_IN_HEADER:\n\t/* copy as many bytes as possible into the buffer. */\n\tif (len + ctx->hdrcount > 10) {\n\t    count = 10 - ctx->hdrcount;\n\t} else {\n\t    count = len;\n\t}\n\tmemcpy(ctx->header + ctx->hdrcount, buf, count);\n\tctx->hdrcount += count;\n\t/* have we got the full header yet? */\n\tif (ctx->hdrcount != 10) {\n\t    return 0;\n\t}\n\n\tbuf += count;\n\tlen -= count;\n\n\tswitch (parse_header(ctx)) {\n\tcase HDR_EXTENDED:\n\t    if (len == 0)\n\t\treturn 0;\n\t    break;\n        case HDR_ERROR:\n            return NE_ERROR;\n\tcase HDR_DONE:\n\t    if (len > 0) {\n\t\treturn do_inflate(ctx, buf, len);\n\t    }\n            break;\n\t}\n\n\t/* FALLTHROUGH */\n\n    case NE_Z_POST_HEADER:\n\t/* eating the filename string. */\n\tzbuf = memchr(buf, '\\0', len);\n\tif (zbuf == NULL) {\n\t    /* not found it yet. */\n\t    return 0;\n\t}\n\n\tNE_DEBUG(NE_DBG_HTTP,\n\t\t \"compress: skipped %\" NE_FMT_SIZE_T \" header bytes.\\n\", \n\t\t zbuf - buf);\n\t/* found end of string. */\n\tlen -= (1 + zbuf - buf);\n\tbuf = zbuf + 1;\n\tctx->state = NE_Z_INFLATING;\n\tif (len == 0) {\n\t    /* end of string was at end of buffer. */\n\t    return 0;\n\t}\n\n\t/* FALLTHROUGH */\n\n    case NE_Z_INFLATING:\n\treturn do_inflate(ctx, buf, len);\n\n    case NE_Z_AFTER_DATA:\n\treturn process_footer(ctx, (unsigned char *)buf, len);\n    }\n\n    return 0;\n}\n\n/* Prepare for a compressed response; may be called many times per\n * request, for auth retries etc. */\nstatic void gz_pre_send(ne_request *r, void *ud, ne_buffer *req)\n{\n    ne_decompress *ctx = ud;\n\n    if (ctx->request == r) {\n        NE_DEBUG(NE_DBG_HTTP, \"compress: Initialization.\\n\");\n        \n        /* (Re-)Initialize the context */\n        ctx->state = NE_Z_BEFORE_DATA;\n        if (ctx->zstrinit) inflateEnd(&ctx->zstr);\n        ctx->zstrinit = 0;\n        ctx->hdrcount = ctx->footcount = 0;\n        ctx->checksum = crc32(0L, Z_NULL, 0);\n    }\n}\n\n/* Wrapper for user-passed acceptor function. */\nstatic int gz_acceptor(void *userdata, ne_request *req, const ne_status *st)\n{\n    ne_decompress *ctx = userdata;\n    return ctx->acceptor(ctx->userdata, req, st);\n}\n\n/* A slightly ugly hack: the pre_send hook is scoped per-session, so\n * must check that the invoking request is this one, before doing\n * anything, and must be unregistered when the context is\n * destroyed. */\nne_decompress *ne_decompress_reader(ne_request *req, ne_accept_response acpt,\n\t\t\t\t    ne_block_reader rdr, void *userdata)\n{\n    ne_decompress *ctx = ne_calloc(sizeof *ctx);\n\n    ne_add_request_header(req, \"Accept-Encoding\", \"gzip\");\n\n    ne_add_response_body_reader(req, gz_acceptor, gz_reader, ctx);\n\n    ctx->reader = rdr;\n    ctx->userdata = userdata;\n    ctx->session = ne_get_session(req);\n    ctx->request = req;\n    ctx->acceptor = acpt;\n\n    ne_hook_pre_send(ne_get_session(req), gz_pre_send, ctx);\n\n    return ctx;    \n}\n\nvoid ne_decompress_destroy(ne_decompress *ctx)\n{\n    if (ctx->zstrinit) inflateEnd(&ctx->zstr);\n\n    ne_unhook_pre_send(ctx->session, gz_pre_send, ctx);\n\n    ne_free(ctx);\n}\n\n#else /* !NE_HAVE_ZLIB */\n\n/* Pass-through interface present to provide ABI compatibility. */\n\nne_decompress *ne_decompress_reader(ne_request *req, ne_accept_response acpt,\n\t\t\t\t    ne_block_reader rdr, void *userdata)\n{\n    ne_add_response_body_reader(req, acpt, rdr, userdata);\n    /* an arbitrary return value: don't confuse them by returning NULL. */\n    return (ne_decompress *)req;\n}\n\nvoid ne_decompress_destroy(ne_decompress *dc)\n{\n}\n\n#endif /* NE_HAVE_ZLIB */\n"
  },
  {
    "path": "src/ne_compress.h",
    "content": "/* \n   Compressed HTTP response handling\n   Copyright (C) 2001-2021, Joe Orton <joe@manyfish.co.uk>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n   \n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n\n#ifndef NE_COMPRESS_H\n#define NE_COMPRESS_H\n\n#include \"ne_request.h\"\n\nNE_BEGIN_DECLS\n\ntypedef struct ne_decompress_s ne_decompress;\n\n/* Call this to register a 'reader' callback which will be passed\n * blocks of response body (if the 'acceptance' callback is\n * successful).  If the response body is returned compressed by the\n * server, this reader will receive UNCOMPRESSED blocks.\n *\n * Returns pointer to context object which must be passed to\n * ne_decompress_destroy after the request has been dispatched, to\n * free any internal state.  If an error occurs during decompression,\n * the request will be aborted and session error string set. */\nne_decompress *ne_decompress_reader(ne_request *req, ne_accept_response accpt,\n\t\t\t\t    ne_block_reader rdr, void *userdata);\n\n/* Destroys decompression state. */\nvoid ne_decompress_destroy(ne_decompress *ctx);\n\nNE_END_DECLS\n\n#endif /* NE_COMPRESS_H */\n"
  },
  {
    "path": "src/ne_dates.c",
    "content": "/* \n   Date manipulation routines\n   Copyright (C) 1999-2021, Joe Orton <joe@manyfish.co.uk>\n   Copyright (C) 2004 Jiang Lei <tristone@deluxe.ocn.ne.jp>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n   \n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n\n#include \"config.h\"\n\n#include <sys/types.h>\n\n#include <time.h>\n#ifdef HAVE_STDLIB_H\n#include <stdlib.h>\n#endif\n#include <stdio.h>\n\n#ifdef HAVE_STRING_H\n#include <string.h>\n#endif\n\n#ifdef WIN32\n#include <windows.h> /* for TIME_ZONE_INFORMATION */\n#endif\n\n#include \"ne_alloc.h\"\n#include \"ne_dates.h\"\n#include \"ne_string.h\"\n\n/* Generic date manipulation routines. */\n\n/* ISO8601: 2001-01-01T12:30:00Z */\n#define ISO8601_FORMAT_Z \"%04d-%02d-%02dT%02d:%02d:%lfZ\"\n#define ISO8601_FORMAT_M \"%04d-%02d-%02dT%02d:%02d:%lf-%02d:%02d\"\n#define ISO8601_FORMAT_P \"%04d-%02d-%02dT%02d:%02d:%lf+%02d:%02d\"\n\n/* IMF-fixdate: Sun, 06 Nov 1994 08:49:37 GMT */\n#define IMFFIX_FORMAT \"%3s, %02d %3s %4d %02d:%02d:%02d GMT\"\n/* RFC850:  Sunday, 06-Nov-94 08:49:37 GMT */\n#define RFC1036_FORMAT \"%10s %2d-%3s-%2d %2d:%2d:%2d GMT\"\n/* asctime: Wed Jun 30 21:49:08 1993 */\n#define ASCTIME_FORMAT \"%3s %3s %2d %2d:%2d:%2d %4d\"\n\nstatic const char rfc1123_weekdays[7][4] = { \n    \"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\" \n};\nstatic const char short_months[12][4] = { \n    \"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\",\n    \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\"\n};\n\n#if defined(HAVE_STRUCT_TM_TM_GMTOFF)\n#define GMTOFF(t) ((t).tm_gmtoff)\n#elif defined(HAVE_STRUCT_TM___TM_GMTOFF)\n#define GMTOFF(t) ((t).__tm_gmtoff)\n#elif defined(WIN32)\n#define GMTOFF(t) (gmt_to_local_win32())\n#elif defined(HAVE_TIMEZONE)\n/* FIXME: the following assumes fixed dst offset of 1 hour */\n#define GMTOFF(t) (-timezone + ((t).tm_isdst > 0 ? 3600 : 0))\n#else\n/* FIXME: work out the offset anyway. */\n#define GMTOFF(t) (0)\n#endif\n\n#ifdef WIN32\ntime_t gmt_to_local_win32(void)\n{\n    TIME_ZONE_INFORMATION tzinfo;\n    DWORD dwStandardDaylight;\n    long bias;\n\n    dwStandardDaylight = GetTimeZoneInformation(&tzinfo);\n    bias = tzinfo.Bias;\n\n    if (dwStandardDaylight == TIME_ZONE_ID_STANDARD)\n        bias += tzinfo.StandardBias;\n    \n    if (dwStandardDaylight == TIME_ZONE_ID_DAYLIGHT)\n        bias += tzinfo.DaylightBias;\n    \n    return (- bias * 60);\n}\n#endif\n\nchar *ne_rfc1123_date(time_t anytime) {\n    struct tm gmt;\n    struct tm *rv;\n    char *ret;\n\n#ifdef HAVE_GMTIME_R\n    if ((rv = gmtime_r(&anytime, &gmt)) == NULL)\n        return NULL;\n#else\n    if ((rv = gmtime(&anytime)) == NULL)\n        return NULL;\n\n    gmt = *rv;\n#endif\n\n    ret = ne_malloc(29 + 1); /* dates are 29 chars long */\n    ne_snprintf(ret, 30, IMFFIX_FORMAT,\n\t\trfc1123_weekdays[gmt.tm_wday], gmt.tm_mday,\n\t\tshort_months[gmt.tm_mon], 1900 + gmt.tm_year,\n\t\tgmt.tm_hour, gmt.tm_min, gmt.tm_sec);\n\n    return ret;\n}\n\n/* Takes an ISO-8601-formatted date string and returns the time_t.\n * Returns (time_t)-1 if the parse fails. */\ntime_t ne_iso8601_parse(const char *date) \n{\n    struct tm gmt = {0};\n    int off_hour, off_min;\n    double sec;\n    off_t fix;\n    time_t result;\n\n    /*  it goes: ISO8601: 2001-01-01T12:30:00+03:30 */\n    if (sscanf(date, ISO8601_FORMAT_P,\n               &gmt.tm_year, &gmt.tm_mon, &gmt.tm_mday,\n               &gmt.tm_hour, &gmt.tm_min, &sec,\n               &off_hour, &off_min) == 8) {\n        gmt.tm_sec = (int)sec;\n        fix = - off_hour * 3600 - off_min * 60;\n    }\n    /*  it goes: ISO8601: 2001-01-01T12:30:00-03:30 */\n    else if (sscanf(date, ISO8601_FORMAT_M,\n                    &gmt.tm_year, &gmt.tm_mon, &gmt.tm_mday,\n                    &gmt.tm_hour, &gmt.tm_min, &sec,\n                    &off_hour, &off_min) == 8) {\n        gmt.tm_sec = (int)sec;\n        fix = off_hour * 3600 + off_min * 60;\n    }\n    /*  it goes: ISO8601: 2001-01-01T12:30:00Z */\n    else if (sscanf(date, ISO8601_FORMAT_Z,\n                    &gmt.tm_year, &gmt.tm_mon, &gmt.tm_mday,\n                    &gmt.tm_hour, &gmt.tm_min, &sec) == 6) {\n        gmt.tm_sec = (int)sec;\n        fix = 0;\n    }\n    else {\n        return (time_t)-1;\n    }\n\n    gmt.tm_year -= 1900;\n    gmt.tm_isdst = -1;\n    gmt.tm_mon--;\n\n    result = mktime(&gmt) + fix;\n    return result + GMTOFF(gmt);\n}\n\ntime_t ne_rfc1123_parse(const char *date) \n{\n    struct tm gmt = {0};\n    char wkday[4], mon[4];\n    int n;\n    time_t result;\n    \n    /* it goes: Sun, 06 Nov 1994 08:49:37 GMT */\n    if (sscanf(date, IMFFIX_FORMAT,\n               wkday, &gmt.tm_mday, mon, &gmt.tm_year, &gmt.tm_hour,\n               &gmt.tm_min, &gmt.tm_sec) != 7)\n        return (time_t) -1;\n\n    gmt.tm_year -= 1900;\n    for (n=0; n<12; n++)\n\tif (strcmp(mon, short_months[n]) == 0)\n\t    break;\n    /* tm_mon comes out as 12 if the month is corrupt, which is desired,\n     * since the mktime will then fail */\n    gmt.tm_mon = n;\n    gmt.tm_isdst = -1;\n    result = mktime(&gmt);\n    return result + GMTOFF(gmt);\n}\n\n/* Takes a string containing a RFC1036-style date and returns the time_t */\ntime_t ne_rfc1036_parse(const char *date) \n{\n    struct tm gmt = {0};\n    int n;\n    char wkday[11], mon[4];\n    time_t result;\n\n    /* RFC850/1036 style dates: Sunday, 06-Nov-94 08:49:37 GMT */\n    n = sscanf(date, RFC1036_FORMAT,\n\t\twkday, &gmt.tm_mday, mon, &gmt.tm_year,\n\t\t&gmt.tm_hour, &gmt.tm_min, &gmt.tm_sec);\n    if (n != 7) {\n\treturn (time_t)-1;\n    }\n\n    for (n=0; n<12; n++)\n\tif (strcmp(mon, short_months[n]) == 0)\n\t    break;\n    /* tm_mon comes out as 12 if the month is corrupt, which is desired,\n     * since the mktime will then fail */\n\n    /* Defeat Y2K bug. */\n    if (gmt.tm_year < 50)\n\tgmt.tm_year += 100;\n\n    gmt.tm_mon = n;\n    gmt.tm_isdst = -1;\n    result = mktime(&gmt);\n    return result + GMTOFF(gmt);\n}\n\n\n/* (as)ctime dates are like:\n *    Wed Jun 30 21:49:08 1993\n */\ntime_t ne_asctime_parse(const char *date) \n{\n    struct tm gmt = {0};\n    int n;\n    char wkday[4], mon[4];\n    time_t result;\n\n    if (sscanf(date, ASCTIME_FORMAT,\n               wkday, mon, &gmt.tm_mday, \n               &gmt.tm_hour, &gmt.tm_min, &gmt.tm_sec,\n               &gmt.tm_year) != 7)\n        return (time_t)-1;\n\n    gmt.tm_year -= 1900;\n    for (n=0; n<12; n++)\n\tif (strcmp(mon, short_months[n]) == 0)\n\t    break;\n    /* tm_mon comes out as 12 if the month is corrupt, which is desired,\n     * since the mktime will then fail */\n    gmt.tm_mon = n;\n    gmt.tm_isdst = -1;\n    result = mktime(&gmt);\n    return result + GMTOFF(gmt);\n}\n\ntime_t ne_httpdate_parse(const char *date)\n{\n    time_t tmp;\n    tmp = ne_rfc1123_parse(date);\n    if (tmp == -1) {\n        tmp = ne_rfc1036_parse(date);\n\tif (tmp == -1)\n\t    tmp = ne_asctime_parse(date);\n    }\n    return tmp;\n}\n"
  },
  {
    "path": "src/ne_dates.h",
    "content": "/* \n   Date manipulation routines\n   Copyright (C) 1999-2021, Joe Orton <joe@manyfish.co.uk>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n   \n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n\n#ifndef NE_DATES_H\n#define NE_DATES_H\n\n#include <sys/types.h>\n\n#include \"ne_defs.h\"\n\nNE_BEGIN_DECLS\n\n/* Convert time to a string following the Internet Message Format RFC\n * standard (historically known as \"RFC1123\", currently known as\n * RFC5322). Returns a malloc-allocated string, or NULL if there is an\n * error converting the time. */\nchar *ne_rfc1123_date(time_t anytime)\n    ne_attribute_malloc;\n\n/* Parses a date/time using the ISO8601 format. Returns -1 on\n * error. */\ntime_t ne_iso8601_parse(const char *date)\n    ne_attribute((nonnull));\n\n/* Parses a date/time using the IMF-fixdate format (historically\n * known as \"RFC1123\". Returns -1 on error. */\ntime_t ne_rfc1123_parse(const char *date)\n    ne_attribute((nonnull));\n\n/* Parses a date/time using the RFC1036 format. Returns -1 on\n * error. */\ntime_t ne_rfc1036_parse(const char *date)\n    ne_attribute((nonnull));\n\n/* Parses a libc \"asctime\" format date. Returns -1 on error. */\ntime_t ne_asctime_parse(const char *date)\n    ne_attribute((nonnull));\n\n/* Parse an HTTP-date as perq RFC2616. Returns -1 on error. */\ntime_t ne_httpdate_parse(const char *date)\n    ne_attribute((nonnull));\n\nNE_END_DECLS\n\n#endif /* NE_DATES_H */\n"
  },
  {
    "path": "src/ne_defs.h",
    "content": "/* \n   Standard definitions for neon headers\n   Copyright (C) 2003-2021, Joe Orton <joe@manyfish.co.uk>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n   \n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n\n#undef NE_BEGIN_DECLS\n#undef NE_END_DECLS\n#ifdef __cplusplus\n# define NE_BEGIN_DECLS extern \"C\" {\n# define NE_END_DECLS }\n#else\n# define NE_BEGIN_DECLS /* empty */\n# define NE_END_DECLS /* empty */\n#endif\n\n#ifndef NE_DEFS_H\n#define NE_DEFS_H\n\n#include <sys/types.h>\n\n#ifdef NE_LFS\n# ifdef _MSC_VER\ntypedef __int64 off64_t;\n# endif\ntypedef off64_t ne_off_t;\n#else\ntypedef off_t ne_off_t;\n#endif\n\n/* define ssize_t for Win32 */\n#if defined(WIN32) && !defined(ssize_t)\n#ifdef _WIN64\n#define ssize_t __int64\n#else\n#define ssize_t int\n#endif\n#endif\n\n#ifdef __NETWARE__\n#include <time.h> /* for time_t */\n#endif\n\n#ifdef __GNUC__\n#if __GNUC__ >= 3\n#ifndef NE_PRIVATE\n#define NE_PRIVATE __attribute__((visibility (\"hidden\")))\n#endif\n#define ne_attribute_malloc __attribute__((malloc))\n#define ne_attribute_alloc_size(x) __attribute__((alloc_size(x)))\n#else\n#define ne_attribute_malloc\n#define ne_attribute_alloc_size(x)\n#endif\n#if __GNUC__ > 3\n#define ne_attribute_sentinel __attribute__((sentinel))\n#else\n#define ne_attribute_sentinel \n#endif\n#define ne_attribute(x) __attribute__(x)\n#else\n#define ne_attribute(x)\n#define ne_attribute_malloc\n#define ne_attribute_alloc_size(x)\n#define ne_attribute_sentinel\n#endif\n\n#ifndef NE_PRIVATE\n#define NE_PRIVATE\n#endif\n\n#ifndef NE_BUFSIZ\n#define NE_BUFSIZ 8192\n#endif\n\n#ifndef NE_VAR\n# if defined(_MSC_VER) && defined(NE_DLL)\n#  ifdef BUILDING_NEON\n#   define NE_VAR extern __declspec(dllexport)\n#  else\n#   define NE_VAR extern __declspec(dllimport)\n#  endif\n# else\n#  define NE_VAR extern\n# endif\n#endif\n\n#endif /* NE_DEFS_H */\n"
  },
  {
    "path": "src/ne_gnutls.c",
    "content": "/*\n   neon SSL/TLS support using GNU TLS\n   Copyright (C) 2002-2021, Joe Orton <joe@manyfish.co.uk>\n   Copyright (C) 2004, Aleix Conchillo Flaque <aleix@member.fsf.org>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n\n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n*/\n\n#include \"config.h\"\n\n#include <sys/types.h>\n\n#ifdef HAVE_STRING_H\n#include <string.h>\n#endif\n\n#include <stdio.h>\n#include <unistd.h>\n#include <stdlib.h>\n#include <errno.h>\n\n#include <gnutls/gnutls.h>\n#include <gnutls/crypto.h>\n#include <gnutls/pkcs12.h>\n\n#ifdef NE_HAVE_TS_SSL\n#include <errno.h>\n#include <pthread.h>\n#if LIBGNUTLS_VERSION_NUMBER < 0x020b01\n#include <gcrypt.h>\nGCRY_THREAD_OPTION_PTHREAD_IMPL;\n#endif\n#else\n#if LIBGNUTLS_VERSION_NUMBER < 0x020b01\n#include <gcrypt.h>\n#endif\n#endif\n\n#ifdef HAVE_ICONV\n#include <iconv.h>\n#endif\n\n#include \"ne_ssl.h\"\n#include \"ne_string.h\"\n#include \"ne_internal.h\"\n#include \"ne_utils.h\"\n#include \"ne_privssl.h\"\n\n#if LIBGNUTLS_VERSION_NUMBER >= 0x020302\n/* The GnuTLS DN functions in 2.3.2 and later allow a simpler DN\n * abstraction to be used. */\n#define HAVE_NEW_DN_API\n#endif\n\nstruct ne_ssl_dname_s {\n#ifdef HAVE_NEW_DN_API\n    gnutls_x509_dn_t dn;\n#else\n    int subject; /* non-zero if this is the subject DN object */\n    gnutls_x509_crt_t cert;\n#endif\n};\n\nstruct ne_ssl_certificate_s {\n    ne_ssl_dname subj_dn, issuer_dn;\n    gnutls_x509_crt_t subject;\n    ne_ssl_certificate *issuer;\n    char *identity;\n};\n\nstruct ne_ssl_client_cert_s {\n    gnutls_pkcs12_t p12;\n    int decrypted; /* non-zero if successfully decrypted. */\n    int keyless;\n    ne_ssl_certificate cert;\n    gnutls_x509_privkey_t pkey;\n    char *friendly_name;\n#ifdef HAVE_GNUTLS_PRIVKEY_IMPORT_EXT\n    /* Signing callback & userdata provided by ne_pkcs11.c.  It would\n     * be better to rewrite the whole module to use gnutls_privkey_t\n     * directly, but it seems impossible to dup such an object. */\n    gnutls_privkey_sign_func sign_func;\n    void *sign_ud;\n#endif\n};\n\n/* Returns the highest used index in subject (or issuer) DN of\n * certificate CERT for OID, or -1 if no RDNs are present in the DN\n * using that OID. */\nstatic int oid_find_highest_index(gnutls_x509_crt_t cert, int subject, const char *oid)\n{\n    int ret, idx = -1;\n\n    do {\n        size_t len = 0;\n\n        if (subject)\n            ret = gnutls_x509_crt_get_dn_by_oid(cert, oid, ++idx, 0, \n                                                NULL, &len);\n        else\n            ret = gnutls_x509_crt_get_issuer_dn_by_oid(cert, oid, ++idx, 0, \n                                                       NULL, &len);\n    } while (ret == GNUTLS_E_SHORT_MEMORY_BUFFER);\n    \n    return idx - 1;\n}\n\n#ifdef HAVE_GNUTLS_X509_DN_GET_RDN_AVA\n/* New-style RDN handling introduced in GnuTLS 1.7.x. */\n\n#ifdef HAVE_ICONV\nstatic void convert_dirstring(ne_buffer *buf, const char *charset, \n                              gnutls_datum_t *data)\n{\n    iconv_t id = iconv_open(\"UTF-8\", charset);\n    size_t inlen = data->size, outlen = buf->length - buf->used;\n    char *inbuf = (char *)data->data;\n    char *outbuf = buf->data + buf->used - 1;\n    \n    if (id == (iconv_t)-1) {\n        char err[128];\n\n        ne_buffer_snprintf(buf, 128, \"[unprintable in %s: %s]\",\n                           charset,\n                           ne_strerror(errno, err, sizeof err));\n        return;\n    }\n    \n    ne_buffer_grow(buf, buf->used + 64);\n    \n    while (inlen && outlen \n           && iconv(id, &inbuf, &inlen, &outbuf, &outlen) == 0)\n        ;\n    \n    iconv_close(id);\n    buf->used += buf->length - buf->used - outlen;\n    buf->data[buf->used - 1] = '\\0';\n}\n#endif\n\n/* From section 11.13 of the Dubuisson ASN.1 bible: */\n#define TAG_UTF8 (12)\n#define TAG_PRINTABLE (19)\n#define TAG_T61 (20)\n#define TAG_IA5 (22)\n#define TAG_VISIBLE (26)\n#define TAG_UNIVERSAL (28)\n#define TAG_BMP (30)\n\nstatic void append_dirstring(ne_buffer *buf, gnutls_datum_t *data, unsigned long tag)\n{\n    switch (tag) {\n    case TAG_UTF8:\n    case TAG_IA5:\n    case TAG_PRINTABLE:\n    case TAG_VISIBLE:\n        ne_buffer_append(buf, (char *)data->data, data->size);\n        break;\n#ifdef HAVE_ICONV\n    case TAG_T61:\n        convert_dirstring(buf, \"ISO-8859-1\", data);\n        break;\n    case TAG_BMP:\n        convert_dirstring(buf, \"UCS-2BE\", data);\n        break;\n#endif\n    default:\n        ne_buffer_snprintf(buf, 128, _(\"[unprintable:#%lu]\"), tag);\n        break;\n    }\n}\n\n/* OIDs to not include in readable DNs by default: */\n#define OID_emailAddress \"1.2.840.113549.1.9.1\"\n#define OID_commonName \"2.5.4.3\"\n\n#define CMPOID(a,o) ((a)->oid.size == sizeof(o)                        \\\n                     && memcmp((a)->oid.data, o, strlen(o)) == 0)\n\nchar *ne_ssl_readable_dname(const ne_ssl_dname *name)\n{\n    gnutls_x509_dn_t dn;\n    int ret, rdn = 0;\n    ne_buffer *buf;\n    gnutls_x509_ava_st val;\n\n#ifdef HAVE_NEW_DN_API\n    dn = name->dn;\n#else\n    if (name->subject)\n        ret = gnutls_x509_crt_get_subject(name->cert, &dn);\n    else\n        ret = gnutls_x509_crt_get_issuer(name->cert, &dn);\n    \n    if (ret)\n        return ne_strdup(_(\"[unprintable]\"));\n#endif /* HAVE_NEW_DN_API */\n\n    buf = ne_buffer_create();\n    \n    /* Find the highest rdn... */\n    while (gnutls_x509_dn_get_rdn_ava(dn, rdn++, 0, &val) == 0)\n        ;        \n\n    /* ..then iterate back to the first: */\n    while (--rdn >= 0) {\n        int ava = 0;\n\n        /* Iterate through all AVAs for multivalued AVAs; better than\n         * ne_openssl can do! */\n        do {\n            ret = gnutls_x509_dn_get_rdn_ava(dn, rdn, ava, &val);\n\n            /* If the *only* attribute to append is the common name or\n             * email address, use it; otherwise skip those\n             * attributes. */\n            if (ret == 0 && val.value.size > 0\n                && ((!CMPOID(&val, OID_emailAddress)\n                     && !CMPOID(&val, OID_commonName))\n                    || (buf->used == 1 && rdn == 0))) {\n                if (buf->used > 1) ne_buffer_append(buf, \", \", 2);\n\n                append_dirstring(buf, &val.value, val.value_tag);\n            }\n            \n            ava++;\n        } while (ret == 0);\n    }\n\n    return ne_buffer_finish(buf);\n}\n\n#else /* !HAVE_GNUTLS_X509_DN_GET_RDN_AVA */\n\n/* Appends the value of RDN with given oid from certitifcate x5\n * subject (if subject is non-zero), or issuer DN to buffer 'buf': */\nstatic void append_rdn(ne_buffer *buf, gnutls_x509_crt_t x5, int subject, const char *oid)\n{\n    int idx, top, ret;\n    char rdn[50];\n\n    top = oid_find_highest_index(x5, subject, oid);\n    \n    for (idx = top; idx >= 0; idx--) {\n        size_t rdnlen = sizeof rdn;\n\n        if (subject)\n            ret = gnutls_x509_crt_get_dn_by_oid(x5, oid, idx, 0, rdn, &rdnlen);\n        else\n            ret = gnutls_x509_crt_get_issuer_dn_by_oid(x5, oid, idx, 0, rdn, &rdnlen);\n        \n        if (ret < 0)\n            return;\n\n        if (buf->used > 1) {\n            ne_buffer_append(buf, \", \", 2);\n        }\n        \n        ne_buffer_append(buf, rdn, rdnlen);\n    }\n}\n\nchar *ne_ssl_readable_dname(const ne_ssl_dname *name)\n{\n    ne_buffer *buf = ne_buffer_create();\n    int ret, idx = 0;\n\n    do {\n        char oid[32] = {0};\n        size_t oidlen = sizeof oid;\n        \n        ret = name->subject \n            ? gnutls_x509_crt_get_dn_oid(name->cert, idx, oid, &oidlen)\n            : gnutls_x509_crt_get_issuer_dn_oid(name->cert, idx, oid, &oidlen);\n        \n        if (ret == 0) {\n            append_rdn(buf, name->cert, name->subject, oid);\n            idx++;\n        }\n    } while (ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);\n\n    return ne_buffer_finish(buf);\n}\n#endif /* HAVE_GNUTLS_X509_DN_GET_RDN_AVA */\n\nint ne_ssl_dname_cmp(const ne_ssl_dname *dn1, const ne_ssl_dname *dn2)\n{\n    char c1[1024], c2[1024];\n    size_t s1 = sizeof c1, s2 = sizeof c2;\n\n#ifdef HAVE_NEW_DN_API\n    if (gnutls_x509_dn_export(dn1->dn, GNUTLS_X509_FMT_DER, c1, &s1))\n        return 1;\n        \n    if (gnutls_x509_dn_export(dn2->dn, GNUTLS_X509_FMT_DER, c2, &s2))\n        return -1;\n#else\n    int ret;\n\n    if (dn1->subject)\n        ret = gnutls_x509_crt_get_dn(dn1->cert, c1, &s1);\n    else\n        ret = gnutls_x509_crt_get_issuer_dn(dn1->cert, c1, &s1);\n    if (ret)\n        return 1;\n\n    if (dn2->subject)\n        ret = gnutls_x509_crt_get_dn(dn2->cert, c2, &s2);\n    else\n        ret = gnutls_x509_crt_get_issuer_dn(dn2->cert, c2, &s2);\n    if (ret)\n        return -1;\n#endif /* HAVE_NEW_DN_API */\n    \n    if (s1 != s2)\n        return s2 - s1;\n\n    return memcmp(c1, c2, s1);\n}\n\nvoid ne_ssl_clicert_free(ne_ssl_client_cert *cc)\n{\n    if (cc->p12)\n        gnutls_pkcs12_deinit(cc->p12);\n    if (cc->decrypted) {\n        if (cc->cert.identity) ne_free(cc->cert.identity);\n        if (cc->pkey) gnutls_x509_privkey_deinit(cc->pkey);\n        if (cc->cert.subject) gnutls_x509_crt_deinit(cc->cert.subject);\n    }\n    if (cc->friendly_name) ne_free(cc->friendly_name);\n    ne_free(cc);\n}\n\nvoid ne_ssl_cert_validity_time(const ne_ssl_certificate *cert,\n                               time_t *from, time_t *until)\n{\n    if (from) {\n        *from = gnutls_x509_crt_get_activation_time(cert->subject);\n    }\n    if (until) {\n        *until = gnutls_x509_crt_get_expiration_time(cert->subject);\n    }\n}\n\n/* Check certificate identity per RFC 2818 and RFC 3280. */\nstatic int check_identity(const ne_ssl_certificate *server_cert,\n                          const char *hostname, const ne_inet_addr *address,\n                          char **identity)\n{\n    char name[255];\n    unsigned int critical;\n    int ret, seq = 0;\n    int match = 0, found = 0;\n    size_t len;\n    gnutls_x509_crt_t cert = server_cert->subject;\n\n    do {\n        len = sizeof name - 1;\n        ret = gnutls_x509_crt_get_subject_alt_name(cert, seq, name, &len,\n                                                   &critical);\n        switch (ret) {\n        case GNUTLS_SAN_DNSNAME:\n            name[len] = '\\0';\n            if (identity && !found) *identity = ne_strdup(name);\n            /* Only match if the server was not identified by a\n             * literal IP address; avoiding wildcard matches. */\n            if (!address)\n                match = ne__ssl_match_hostname(name, len, hostname);\n            found = 1;\n            break;\n        case GNUTLS_SAN_IPADDRESS: {\n            ne_inet_addr *ia;\n            if (len == 4)\n                ia = ne_iaddr_make(ne_iaddr_ipv4, (unsigned char *)name);\n            else if (len == 16)\n                ia = ne_iaddr_make(ne_iaddr_ipv6, (unsigned char *)name);\n            else \n                ia = NULL;\n            if (ia) {\n                if (address)\n                    match = ne_iaddr_cmp(ia, address) == 0;\n                found = 1;\n                ne_iaddr_free(ia);\n            }\n            else {\n                NE_DEBUG(NE_DBG_SSL, \"iPAddress name with unsupported \"\n                         \"address type (length %\" NE_FMT_SIZE_T \"), skipped.\\n\",\n                         len);\n            }\n        } break;\n\n        default:\n            break;\n        }\n        seq++;\n    } while (!match && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);\n\n    /* Check against the commonName if no DNS alt. names were found,\n     * as per RFC3280. */\n    if (!found) {\n        seq = oid_find_highest_index(cert, 1, GNUTLS_OID_X520_COMMON_NAME);\n\n        if (seq >= 0) {\n            len = sizeof name;\n            name[0] = '\\0';\n            ret = gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME,\n                                                seq, 0, name, &len);\n            if (ret == 0) {\n                if (identity) *identity = ne_strdup(name);\n                if (!address)\n                    match = ne__ssl_match_hostname(name, len, hostname);\n            }\n        } else {\n            return -1;\n        }\n    }\n\n    if (hostname)\n        NE_DEBUG(NE_DBG_SSL, \"ssl: Identity match for '%s': %s\\n\", hostname, \n                 match ? \"good\" : \"bad\");\n\n    return match ? 0 : 1;\n}\n\n/* Populate an ne_ssl_certificate structure from an X509 object.  Note\n * that x5 is owned by returned cert object and must not be otherwise\n * freed by the caller.  */\nstatic ne_ssl_certificate *populate_cert(ne_ssl_certificate *cert,\n                                         gnutls_x509_crt_t x5)\n{\n#ifdef HAVE_NEW_DN_API\n    gnutls_x509_crt_get_subject(x5, &cert->subj_dn.dn);\n    gnutls_x509_crt_get_issuer(x5, &cert->issuer_dn.dn);\n#else\n    cert->subj_dn.cert = x5;\n    cert->subj_dn.subject = 1;\n    cert->issuer_dn.cert = x5;\n    cert->issuer_dn.subject = 0;\n#endif\n    cert->issuer = NULL;\n    cert->subject = x5;\n    cert->identity = NULL;\n    check_identity(cert, NULL, NULL, &cert->identity);\n    return cert;\n}\n\n/* Returns a copy certificate of certificate SRC. */\nstatic gnutls_x509_crt_t x509_crt_copy(gnutls_x509_crt_t src)\n{\n    int ret;\n    size_t size = 0;\n    gnutls_datum_t tmp;\n    gnutls_x509_crt_t dest;\n    \n    if (gnutls_x509_crt_init(&dest) != 0) {\n        return NULL;\n    }\n\n    if (gnutls_x509_crt_export(src, GNUTLS_X509_FMT_DER, NULL, &size) \n        != GNUTLS_E_SHORT_MEMORY_BUFFER) {\n        gnutls_x509_crt_deinit(dest);\n        return NULL;\n    }\n\n    tmp.data = ne_malloc(size);\n    ret = gnutls_x509_crt_export(src, GNUTLS_X509_FMT_DER, tmp.data, &size);\n    if (ret == 0) {\n        tmp.size = size;\n        ret = gnutls_x509_crt_import(dest, &tmp, GNUTLS_X509_FMT_DER);\n    }\n\n    if (ret) {\n        gnutls_x509_crt_deinit(dest);\n        dest = NULL;\n    }\n\n    ne_free(tmp.data);\n    return dest;\n}\n\nne_ssl_client_cert *ne_ssl_clicert_copy(const ne_ssl_client_cert *cc)\n{\n    int ret;\n    ne_ssl_client_cert *newcc = ne_calloc(sizeof *newcc);\n\n    newcc->decrypted = 1;\n    \n    if (cc->keyless) {\n        newcc->keyless = 1;\n#ifdef HAVE_GNUTLS_PRIVKEY_IMPORT_EXT\n        newcc->sign_func = cc->sign_func;\n        newcc->sign_ud = cc->sign_ud;\n#endif\n    }\n    else {\n        ret = gnutls_x509_privkey_init(&newcc->pkey);\n        if (ret != 0) goto dup_error;\n        \n        ret = gnutls_x509_privkey_cpy(newcc->pkey, cc->pkey);\n        if (ret != 0) goto dup_error;\n    }    \n\n    newcc->cert.subject = x509_crt_copy(cc->cert.subject);\n    if (!newcc->cert.subject) goto dup_error;\n\n    if (cc->friendly_name) newcc->friendly_name = ne_strdup(cc->friendly_name);\n\n    populate_cert(&newcc->cert, newcc->cert.subject);\n    return newcc;\n\ndup_error:\n    if (newcc->pkey) gnutls_x509_privkey_deinit(newcc->pkey);\n    if (newcc->cert.subject) gnutls_x509_crt_deinit(newcc->cert.subject);\n    ne_free(newcc);\n    return NULL;\n}    \n\n/* Callback invoked when the SSL server requests a client certificate.  */\nstatic int provide_client_cert(gnutls_session_t session,\n                               const gnutls_datum_t *req_ca_rdn, int nreqs,\n                               const gnutls_pk_algorithm_t *sign_algos,\n                               int sign_algos_length, \n#ifdef HAVE_GNUTLS_CERTIFICATE_SET_RETRIEVE_FUNCTION2\n                               gnutls_pcert_st **pcert, \n                               unsigned int *pcert_length, \n                               gnutls_privkey_t *pkey\n#else\n                               gnutls_retr2_st *st\n#endif\n    )\n{\n    ne_socket *sock = gnutls_session_get_ptr(session);\n    ne_ssl_socket *sslsock;\n    ne_ssl_context *ctx;\n\n    if (!sock) {\n        return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;\n    }\n\n    sslsock = ne__sock_sslsock(sock);\n    ctx = sslsock->context;\n\n    NE_DEBUG(NE_DBG_SSL, \"ssl: Client cert provider callback; %d CA names.\\n\",\n             nreqs);\n\n    if (!ctx->client_cert && ctx->provider) {\n#ifdef HAVE_NEW_DN_API\n        const ne_ssl_dname **dns;\n        ne_ssl_dname *dnarray;\n        unsigned dncount = 0;\n        int n;\n\n        dns = ne_malloc(nreqs * sizeof(ne_ssl_dname *));\n        dnarray = ne_calloc(nreqs * sizeof(ne_ssl_dname));\n\n        for (n = 0; n < nreqs; n++) {\n            gnutls_x509_dn_t dn;\n\n            if (gnutls_x509_dn_init(&dn) == 0) {\n                dnarray[n].dn = dn;\n                if (gnutls_x509_dn_import(dn, &req_ca_rdn[n]) == 0) {\n                    dns[dncount++] = &dnarray[n];\n                }\n                else {\n                    gnutls_x509_dn_deinit(dn);\n                }            \n            }\n        }\n       \n        NE_DEBUG(NE_DBG_SSL, \"ssl: Mapped %d CA names to %u DN objects.\\n\",\n                 nreqs, dncount);\n\n        ctx->provider(ctx->provider_ud, dns, dncount);\n        \n        for (n = 0; n < nreqs; n++) {\n            if (dnarray[n].dn) {\n                gnutls_x509_dn_deinit(dnarray[n].dn);\n            }\n        }\n\n        ne_free(dns);\n        ne_free(dnarray);\n#else /* HAVE_NEW_DN_API */\n        /* Nothing to do here other than pretend no CA names were\n         * given, and hope the caller can cope. */\n        ctx->provider(ctx->provider_ud, NULL, 0);\n#endif\n    }\n\n    if (ctx->client_cert) {\n        gnutls_certificate_type_t type = gnutls_certificate_type_get(session);\n        ne_ssl_client_cert *cc = ctx->client_cert;\n\n        if (type == GNUTLS_CRT_X509 && (cc->pkey || cc->keyless)) {\n            int ret;\n\n#ifdef HAVE_GNUTLS_CERTIFICATE_SET_RETRIEVE_FUNCTION2\n            *pkey = gnutls_malloc(sizeof *pkey);\n            gnutls_privkey_init(pkey);\n\n#ifdef HAVE_GNUTLS_PRIVKEY_IMPORT_EXT\n            if (cc->sign_func) {\n                int algo = gnutls_x509_crt_get_pk_algorithm(cc->cert.subject, NULL);\n                NE_DEBUG(NE_DBG_SSL, \"ssl: Signing for %s.\\n\", gnutls_pk_algorithm_get_name(algo));\n                         \n                ret = gnutls_privkey_import_ext(*pkey, algo, cc->sign_ud,\n                                                cc->sign_func, NULL, 0);\n            }\n            else\n#endif\n            if (cc->keyless) {\n                ret = GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE;\n            }\n            else {\n                ret = gnutls_privkey_import_x509(*pkey, cc->pkey, 0);\n            }\n\n            if (ret) {\n                NE_DEBUG(NE_DBG_SSL, \"ssl: Failed to import private key: %s.\\n\", gnutls_strerror(ret));\n                ne_sock_set_error(sock, _(\"Failed to import private key: %s\"),\n                                  gnutls_strerror(ret));\n                return ret;\n            }\n            \n            *pcert = gnutls_calloc(1, sizeof **pcert);\n            gnutls_pcert_import_x509(*pcert, cc->cert.subject, 0);\n            *pcert_length = 1;\n#else /* !HAVE_GNUTLS_CERTIFICATE_SET_RETRIEVE_FUNCTION2 */\n            st->cert_type = type;\n            st->ncerts = 1;\n            st->cert.x509 = &cc->cert.subject;\n            st->key.x509 = cc->pkey;\n            \n            /* tell GNU TLS not to deallocate the certs. */\n            st->deinit_all = 0;\n#endif\n        } else {\n            return GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE;\n        }\n    } \n    else {\n        NE_DEBUG(NE_DBG_SSL, \"ssl: No client certificate supplied.\\n\");\n#ifdef HAVE_GNUTLS_CERTIFICATE_SET_RETRIEVE_FUNCTION2\n        *pcert_length = 0;\n#else        \n        st->ncerts = 0;\n#endif\n        sslsock->cc_requested = 1;\n        return 0;\n    }\n\n    return 0;\n}\n\nne_ssl_context *ne_ssl_context_create(int flags)\n{\n    ne_ssl_context *ctx = ne_calloc(sizeof *ctx);\n    gnutls_certificate_allocate_credentials(&ctx->cred);\n    if (flags == NE_SSL_CTX_CLIENT) {\n#ifdef HAVE_GNUTLS_CERTIFICATE_SET_RETRIEVE_FUNCTION2\n        gnutls_certificate_set_retrieve_function2(ctx->cred, provide_client_cert);\n#else\n        gnutls_certificate_client_set_retrieve_function(ctx->cred,\n                                                        provide_client_cert);\n#endif\n    }\n    gnutls_certificate_set_verify_flags(ctx->cred, \n                                        GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);\n    return ctx;\n}\n\nint ne_ssl_context_keypair(ne_ssl_context *ctx, \n                           const char *cert, const char *key)\n{\n    gnutls_certificate_set_x509_key_file(ctx->cred, cert, key,\n                                         GNUTLS_X509_FMT_PEM);\n    return 0;\n}\n\nint ne_ssl_context_set_verify(ne_ssl_context *ctx, int required,\n                              const char *ca_names, const char *verify_cas)\n{\n    ctx->verify = required;\n    if (verify_cas) {\n        gnutls_certificate_set_x509_trust_file(ctx->cred, verify_cas,\n                                               GNUTLS_X509_FMT_PEM);\n    }\n    /* gnutls_certificate_send_x509_rdn_sequence in gnutls >= 1.2 can\n     * be used to *suppress* sending the CA names, but not control it,\n     * it seems. */\n    return 0;\n}\n\nvoid ne_ssl_context_set_flag(ne_ssl_context *ctx, int flag, int value)\n{\n}\n\nint ne_ssl_context_get_flag(ne_ssl_context *ctx, int flag)\n{\n    return 0;\n}\n\nint ne_ssl_context_set_versions(ne_ssl_context *ctx, enum ne_ssl_protocol min,\n                                enum ne_ssl_protocol max)\n{\n#ifdef HAVE_GNUTLS_SET_DEFAULT_PRIORITY_APPEND\n    ne_buffer *prio;\n\n    if (min > max) return NE_SOCK_ERROR;\n\n    if (ctx->priority) {\n        ne_free(ctx->priority);\n        ctx->priority = NULL;\n    }\n\n    if (min == 0 && max == 0) {\n        return 0;\n    }\n\n    prio = ne_buffer_create();\n    ne_buffer_czappend(prio, \"+VERS-ALL\");\n\n    if (min > NE_SSL_PROTO_SSL_3)\n        ne_buffer_czappend(prio, \":-VERS-SSL3.0\");\n    if (min > NE_SSL_PROTO_TLS_1_0)\n        ne_buffer_czappend(prio, \":-VERS-TLS1.0\");\n    if (min > NE_SSL_PROTO_TLS_1_1)\n        ne_buffer_czappend(prio, \":-VERS-TLS1.1\");\n    if (min > NE_SSL_PROTO_TLS_1_2)\n        ne_buffer_czappend(prio, \":-VERS-TLS1.2\");\n\n    if (max && max < NE_SSL_PROTO_TLS_1_3)\n        ne_buffer_czappend(prio, \":-VERS-TLS1.3\");\n    if (max && max < NE_SSL_PROTO_TLS_1_2)\n        ne_buffer_czappend(prio, \":-VERS-TLS1.2\");\n    if (max && max < NE_SSL_PROTO_TLS_1_1)\n        ne_buffer_czappend(prio, \":-VERS-TLS1.1\");\n    if (max && max < NE_SSL_PROTO_TLS_1_0)\n        ne_buffer_czappend(prio, \":-VERS-TLS1.0\");\n\n    ctx->priority = ne_buffer_finish(prio);\n\n    return 0;\n#else\n    return NE_SOCK_ERROR;\n#endif\n}\n\nvoid ne_ssl_context_destroy(ne_ssl_context *ctx)\n{\n    gnutls_certificate_free_credentials(ctx->cred);\n    if (ctx->cache.client.data) {\n#if defined(HAVE_GNUTLS_SESSION_GET_DATA2)\n        gnutls_free(ctx->cache.client.data);\n#else\n        ne_free(ctx->cache.client.data);\n#endif\n    } else if (ctx->cache.server.key.data) {\n        gnutls_free(ctx->cache.server.key.data);\n        gnutls_free(ctx->cache.server.data.data);\n    }\n    if (ctx->priority) ne_free(ctx->priority);\n    if (ctx->client_cert) ne_ssl_clicert_free(ctx->client_cert);\n    ne_free(ctx);\n}\n\n#if !defined(HAVE_GNUTLS_CERTIFICATE_GET_ISSUER) && defined(HAVE_GNUTLS_CERTIFICATE_GET_X509_CAS)\n/* Return the issuer of the given certificate, or NULL if none can be\n * found. */\nstatic gnutls_x509_crt_t find_issuer(gnutls_x509_crt_t *ca_list,\n                                   unsigned int num_cas,\n                                   gnutls_x509_crt_t cert)\n{\n    unsigned int n;\n\n    for (n = 0; n < num_cas; n++) {\n        if (gnutls_x509_crt_check_issuer(cert, ca_list[n]) == 1)\n            return ca_list[n];\n    }\n\n    return NULL;\n}\n#endif\n\n/* Return the certificate chain sent by the peer, or NULL on error. */\nne_ssl_certificate *ne__ssl_make_chain(gnutls_session_t sock,\n                                       gnutls_certificate_credentials_t crd)\n{\n    ne_ssl_certificate *current = NULL, *top = NULL;\n    const gnutls_datum_t *certs;\n    unsigned int n, count;\n    ne_ssl_certificate *cert;\n\n    certs = gnutls_certificate_get_peers(sock, &count);\n    if (!certs) {\n        return NULL;\n    }\n\n    NE_DEBUG(NE_DBG_SSL, \"ssl: Got %u certs in peer chain.\\n\", count);\n    \n    for (n = 0; n < count; n++) {\n        gnutls_x509_crt_t x5;\n\n        if (gnutls_x509_crt_init(&x5) ||\n            gnutls_x509_crt_import(x5, &certs[n], GNUTLS_X509_FMT_DER)) {\n            if (top) {\n                ne_ssl_cert_free(top);\n            }\n            return NULL;\n        }\n\n        cert = populate_cert(ne_calloc(sizeof *cert), x5);\n        \n        if (top == NULL) {\n            current = top = cert;\n        } else {\n            current->issuer = cert;\n            current = cert;\n        }\n    }\n\n#if defined(HAVE_GNUTLS_CERTIFICATE_GET_ISSUER) || defined(HAVE_GNUTLS_CERTIFICATE_GET_X509_CAS)\n    /* GnuTLS only returns the peers which were *sent* by the server\n     * in the Certificate list during the handshake.  Fill in the\n     * complete chain manually against the certs we trust: */\n    if (current->issuer == NULL) {\n        gnutls_x509_crt_t issuer;\n\n#ifndef HAVE_GNUTLS_CERTIFICATE_GET_ISSUER\n        gnutls_x509_crt_t *ca_list;\n        unsigned int num_cas;\n        \n        gnutls_certificate_get_x509_cas(crd, &ca_list, &num_cas);\n#endif\n\n        do { \n            /* Look up the issuer. */\n#ifndef HAVE_GNUTLS_CERTIFICATE_GET_ISSUER\n            issuer = find_issuer(ca_list, num_cas, current->subject);\n#else\n            if (gnutls_certificate_get_issuer(crd, current->subject, &issuer, 0))\n                issuer = NULL;\n#endif\n\n            if (issuer) {\n                issuer = x509_crt_copy(issuer);\n                if (issuer == NULL)\n                    break;\n\n                cert = populate_cert(ne_calloc(sizeof *cert), issuer);\n                /* Check that the issuer does not match the current\n                 * cert. */\n                if (ne_ssl_cert_cmp(current, cert)) {\n                    current = current->issuer = cert;\n                }\n                else {\n                    ne_ssl_cert_free(cert);\n                    issuer = NULL;\n                }\n            }\n        } while (issuer);\n    }\n#endif\n    \n    return top;\n}\n\n/* Map from GnuTLS verify failure mask *status to NE_SSL_* failure\n * bitmask, which is returned.  *status is modified, removing all\n * mapped bits. */\nstatic int map_verify_failures(unsigned int *status)\n{\n    static const struct {\n        gnutls_certificate_status_t from;\n        int to;\n    } map[] = {\n        { GNUTLS_CERT_REVOKED, NE_SSL_REVOKED },\n#if LIBGNUTLS_VERSION_NUMBER >= 0x020800\n        { GNUTLS_CERT_NOT_ACTIVATED, NE_SSL_NOTYETVALID },\n        { GNUTLS_CERT_EXPIRED, NE_SSL_EXPIRED },\n#endif\n        { GNUTLS_CERT_INVALID|GNUTLS_CERT_SIGNER_NOT_FOUND, NE_SSL_UNTRUSTED },\n        { GNUTLS_CERT_INVALID|GNUTLS_CERT_SIGNER_NOT_CA, NE_SSL_UNTRUSTED }\n    };\n    size_t n;\n    int ret = 0;\n\n    for (n = 0; n < sizeof(map)/sizeof(map[0]); n++) {\n        if ((*status & map[n].from) == map[n].from) {\n            *status &= ~map[n].from;\n            ret |= map[n].to;\n        }\n    }\n\n    return ret;\n}\n\n/* Return a malloc-allocated human-readable error string describing\n * GnuTLS verification error bitmask 'status'; return value must be\n * freed by the caller. */\nstatic char *verify_error_string(unsigned int status)\n{\n    ne_buffer *buf = ne_buffer_create();\n\n    /* sorry, i18n-ers */\n    if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {\n        ne_buffer_zappend(buf, _(\"signed using insecure algorithm\"));\n    }\n    else {\n        ne_buffer_snprintf(buf, 64, _(\"unrecognized errors (%u)\"),\n                           status);\n    }\n    \n    return ne_buffer_finish(buf);\n}\n\n/* Return NE_SSL_* failure bits after checking chain expiry. */\nstatic int check_chain_expiry(const ne_ssl_certificate *chain)\n{\n    time_t before, after, now = time(NULL);\n    const ne_ssl_certificate *cert;\n    int failures = 0;\n    \n    /* Check that all certs within the chain are inside their defined\n     * validity period.  Note that the errors flagged for the server\n     * cert are different from the generic error for issues higher up\n     * the chain. */\n    for (cert = chain; cert; cert = cert->issuer) {\n        before = gnutls_x509_crt_get_activation_time(cert->subject);\n        after = gnutls_x509_crt_get_expiration_time(cert->subject);\n        \n        if (now < before)\n            failures |= (cert == chain) ? NE_SSL_NOTYETVALID : NE_SSL_BADCHAIN;\n        else if (now > after)\n            failures |= (cert == chain) ? NE_SSL_EXPIRED : NE_SSL_BADCHAIN;\n    }\n\n    return failures;\n}\n\nint ne_ssl_check_certificate(ne_ssl_context *ctx, ne_socket *sock,\n                             const char *hostname, const ne_inet_addr *address,\n                             const ne_ssl_certificate *cert,\n                             unsigned int flags, int *failures_out)\n{\n    ne_ssl_socket *sslsock = ne__sock_sslsock(sock);\n    int ret, failures = 0;\n    unsigned int status;\n\n    ret = check_identity(cert, hostname, address, NULL);\n    if (ret < 0) {\n        ne_sock_set_error(sock, _(\"Server certificate was missing commonName \"\n                                  \"attribute in subject name\"));\n        return NE_SOCK_ERROR;\n    } \n    else if (ret > 0) {\n        failures |= NE_SSL_IDMISMATCH;\n    }\n    \n    failures |= check_chain_expiry(cert);\n\n    ret = gnutls_certificate_verify_peers2(sslsock->sess, &status);\n    NE_DEBUG(NE_DBG_SSL, \"ssl: Verify peers returned %d, status=%u\\n\", \n             ret, status);\n    if (ret != GNUTLS_E_SUCCESS) {\n        ne_sock_set_error(sock, _(\"Could not verify server certificate: %s\"),\n                          gnutls_strerror(ret));\n        return NE_SOCK_ERROR;\n    }\n\n    ret = map_verify_failures(&status);\n    /* For CA expiry/not-yet-valid, mask out the failure bits if\n     * they've been caught and treated as chain errors already by check_chain_expiry(). */\n    if ((ret & (NE_SSL_EXPIRED|NE_SSL_NOTYETVALID)) != 0\n        && (failures & NE_SSL_BADCHAIN) == NE_SSL_BADCHAIN) {\n        ret &= ~(NE_SSL_EXPIRED|NE_SSL_NOTYETVALID);\n    }\n    failures |= ret;\n\n    NE_DEBUG(NE_DBG_SSL, \"ssl: Verification failures %d => %d (status = %u).\\n\",\n             ret, failures, status);\n    \n    if (status && status != GNUTLS_CERT_INVALID) {\n        char *errstr = verify_error_string(status);\n        ne_sock_set_error(sock, _(\"Certificate verification error: %s\"),\n                          errstr);\n        ne_free(errstr);\n        return NE_SOCK_ERROR;\n    }\n\n    if (failures) {\n        /* Pass up the failures for possible override. */\n        ne__sock_set_verify_err(sock, failures);\n        *failures_out = failures;\n        return NE_SOCK_ERROR;\n    }\n\n    return 0;\n}\n\nconst ne_ssl_dname *ne_ssl_cert_issuer(const ne_ssl_certificate *cert)\n{\n    return &cert->issuer_dn;\n}\n\nconst ne_ssl_dname *ne_ssl_cert_subject(const ne_ssl_certificate *cert)\n{\n    return &cert->subj_dn;\n}\n\nconst ne_ssl_certificate *ne_ssl_cert_signedby(const ne_ssl_certificate *cert)\n{\n    return cert->issuer;\n}\n\nconst char *ne_ssl_cert_identity(const ne_ssl_certificate *cert)\n{\n    return cert->identity;\n}\n\nvoid ne_ssl_context_trustcert(ne_ssl_context *ctx, const ne_ssl_certificate *cert)\n{\n    gnutls_x509_crt_t certs = cert->subject;\n    gnutls_certificate_set_x509_trust(ctx->cred, &certs, 1);\n}\n\nvoid ne_ssl_context_set_clicert(ne_ssl_context *ctx, const ne_ssl_client_cert *cc)\n{\n    if (ctx->client_cert) ne_ssl_clicert_free(ctx->client_cert);\n    ctx->client_cert = ne_ssl_clicert_copy(cc);\n}\n\nvoid ne_ssl_context_trustdefca(ne_ssl_context *ctx)\n{\n#ifdef NE_SSL_CA_BUNDLE\n    gnutls_certificate_set_x509_trust_file(ctx->cred,\n                                           NE_SSL_CA_BUNDLE,\n                                           GNUTLS_X509_FMT_PEM);\n#elif defined(HAVE_GNUTLS_CERTIFICATE_SET_X509_SYSTEM_TRUST)\n    int rv = gnutls_certificate_set_x509_system_trust(ctx->cred);\n\n    NE_DEBUG(NE_DBG_SSL, \"ssl: System certificates trusted (%d)\\n\", rv);\n#endif\n}\n\n/* Read the contents of file FILENAME into *DATUM. */\nstatic int read_to_datum(const char *filename, gnutls_datum_t *datum)\n{\n    FILE *f = fopen(filename, \"r\");\n    ne_buffer *buf;\n    char tmp[4192];\n    size_t len;\n\n    if (!f) {\n        return -1;\n    }\n\n    buf = ne_buffer_ncreate(8192);\n    while ((len = fread(tmp, 1, sizeof tmp, f)) > 0) {\n        ne_buffer_append(buf, tmp, len);\n    }\n\n    if (!feof(f)) {\n        fclose(f);\n        ne_buffer_destroy(buf);\n        return -1;\n    }\n    \n    fclose(f);\n\n    datum->size = ne_buffer_size(buf);\n    datum->data = (unsigned char *)ne_buffer_finish(buf);\n    return 0;\n}\n\n/* Parses a PKCS#12 structure and loads the certificate, private key\n * and friendly name if possible.  Returns zero on success, non-zero\n * on error. */\nstatic int pkcs12_parse(gnutls_pkcs12_t p12, gnutls_x509_privkey_t *pkey,\n                        gnutls_x509_crt_t *x5, char **friendly_name,\n                        const char *password)\n{\n    gnutls_pkcs12_bag_t bag = NULL;\n    int i, j, ret = 0;\n\n    for (i = 0; ret == 0; ++i) {\n        if (bag) gnutls_pkcs12_bag_deinit(bag);\n\n        ret = gnutls_pkcs12_bag_init(&bag);\n        if (ret < 0) continue;\n\n        ret = gnutls_pkcs12_get_bag(p12, i, bag);\n        if (ret < 0) continue;\n\n        gnutls_pkcs12_bag_decrypt(bag, password);\n\n        for (j = 0; ret == 0 && j < gnutls_pkcs12_bag_get_count(bag); ++j) {\n            gnutls_pkcs12_bag_type_t type;\n            gnutls_datum_t data;\n\n            if (friendly_name && *friendly_name == NULL) {\n                char *name = NULL;\n                gnutls_pkcs12_bag_get_friendly_name(bag, j, &name);\n                if (name) {\n                    if (name[0] == '.') name++; /* weird GnuTLS bug? */\n                    *friendly_name = ne_strdup(name);\n                }\n            }\n\n            type = gnutls_pkcs12_bag_get_type(bag, j);\n            switch (type) {\n            case GNUTLS_BAG_PKCS8_KEY:\n            case GNUTLS_BAG_PKCS8_ENCRYPTED_KEY:\n                /* Ignore any but the first key encountered; really\n                 * need to match up keyids. */\n                if (*pkey) break;\n\n                gnutls_x509_privkey_init(pkey);\n\n                ret = gnutls_pkcs12_bag_get_data(bag, j, &data);\n                if (ret < 0) continue;\n\n                ret = gnutls_x509_privkey_import_pkcs8(*pkey, &data,\n                                                       GNUTLS_X509_FMT_DER,\n                                                       password,\n                                                       0);\n                if (ret < 0) continue;\n                break;\n            case GNUTLS_BAG_CERTIFICATE:\n                /* Ignore any but the first cert encountered; again,\n                 * really need to match up keyids. */\n                if (*x5) break;\n\n                ret = gnutls_x509_crt_init(x5);\n                if (ret < 0) continue;\n\n                ret = gnutls_pkcs12_bag_get_data(bag, j, &data);\n                if (ret < 0) continue;\n\n                ret = gnutls_x509_crt_import(*x5, &data, GNUTLS_X509_FMT_DER);\n                if (ret < 0) continue;\n\n                break;\n            default:\n                break;\n            }\n        }\n    }\n\n    /* Make sure last bag is freed */\n    if (bag) gnutls_pkcs12_bag_deinit(bag);\n\n    /* Free in case of error */\n    if (ret < 0 && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {\n        if (*x5) gnutls_x509_crt_deinit(*x5);\n        if (*pkey) gnutls_x509_privkey_deinit(*pkey);\n        if (friendly_name && *friendly_name) ne_free(*friendly_name);\n    }\n\n    if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) ret = 0;\n    return ret;\n}\n\nne_ssl_client_cert *ne_ssl_clicert_read(const char *filename)\n{\n    gnutls_datum_t datum;\n    ne_ssl_client_cert *cc;\n\n    if (read_to_datum(filename, &datum))\n        return NULL;\n\n    cc = ne_ssl_clicert_import(datum.data, datum.size);\n\n    ne_free(datum.data);\n\n    return cc;\n}\n\nne_ssl_client_cert *ne_ssl_clicert_import(const unsigned char *buffer, size_t buflen)\n{\n    int ret;\n    gnutls_datum_t data;\n    gnutls_pkcs12_t p12;\n    ne_ssl_client_cert *cc;\n    char *friendly_name = NULL;\n    gnutls_x509_crt_t cert = NULL;\n    gnutls_x509_privkey_t pkey = NULL;\n\n    /* The datum structure is not modified by gnutls_pkcs12_import,\n     * cast safely: */\n    data.data = (unsigned char *)buffer;\n    data.size = buflen;\n\n    if (gnutls_pkcs12_init(&p12) != 0) {\n        return NULL;\n    }\n\n    ret = gnutls_pkcs12_import(p12, &data, GNUTLS_X509_FMT_DER, 0);\n    if (ret < 0) {\n        gnutls_pkcs12_deinit(p12);\n        return NULL;\n    }\n\n    if (gnutls_pkcs12_verify_mac(p12, \"\") == 0) {\n        if (pkcs12_parse(p12, &pkey, &cert, &friendly_name, \"\") != 0\n            || !cert || !pkey) {\n            gnutls_pkcs12_deinit(p12);\n            return NULL;\n        }\n\n        cc = ne_calloc(sizeof *cc);\n        cc->pkey = pkey;\n        cc->decrypted = 1;\n        cc->friendly_name = friendly_name;\n        populate_cert(&cc->cert, cert);\n        gnutls_pkcs12_deinit(p12);\n        cc->p12 = NULL;\n        return cc;\n    } else {\n        /* TODO: calling pkcs12_parse() here to find the friendly_name\n         * seems to break horribly.  */\n        cc = ne_calloc(sizeof *cc);\n        cc->p12 = p12;\n        return cc;\n    }\n}\n\nne_ssl_client_cert *ne_ssl_clicert_fromuri(const char *uri,\n                                           unsigned int flags)\n{\n    errno = ENOTSUP;\n    return NULL;\n}\n\n#ifdef HAVE_GNUTLS_PRIVKEY_IMPORT_EXT\nne_ssl_client_cert *ne__ssl_clicert_exkey_import(const unsigned char *der, size_t der_len,\n                                                 gnutls_privkey_sign_func sign_func,\n                                                 void *userdata)\n{\n    ne_ssl_client_cert *cc;\n    gnutls_x509_crt_t x5;\n    gnutls_datum_t datum;\n\n    datum.data = (unsigned char *)der;\n    datum.size = der_len;    \n\n    if (gnutls_x509_crt_init(&x5) \n        || gnutls_x509_crt_import(x5, &datum, GNUTLS_X509_FMT_DER)) {\n        NE_DEBUG(NE_DBG_SSL, \"ssl: crt_import failed.\\n\");\n        return NULL;\n    }\n    \n    cc = ne_calloc(sizeof *cc);\n    cc->keyless = 1;\n    cc->decrypted = 1;\n    populate_cert(&cc->cert, x5);\n    cc->sign_func = sign_func;\n    cc->sign_ud = userdata;\n\n    return cc;\n}\n#endif\n\nint ne_ssl_clicert_encrypted(const ne_ssl_client_cert *cc)\n{\n    return !cc->decrypted;\n}\n\nint ne_ssl_clicert_decrypt(ne_ssl_client_cert *cc, const char *password)\n{\n    int ret;\n    gnutls_x509_crt_t cert = NULL;\n    gnutls_x509_privkey_t pkey = NULL;\n\n    if (gnutls_pkcs12_verify_mac(cc->p12, password) != 0) {\n        return -1;\n    }        \n\n    ret = pkcs12_parse(cc->p12, &pkey, &cert, NULL, password);\n    if (ret < 0)\n        return ret;\n    \n    if (!cert || (!pkey && !cc->keyless)) {\n        if (cert) gnutls_x509_crt_deinit(cert);\n        if (pkey) gnutls_x509_privkey_deinit(pkey);\n        return -1;\n    }\n\n    gnutls_pkcs12_deinit(cc->p12);\n    populate_cert(&cc->cert, cert);\n    cc->pkey = pkey;\n    cc->decrypted = 1;\n    cc->p12 = NULL;\n    return 0;\n}\n\nconst ne_ssl_certificate *ne_ssl_clicert_owner(const ne_ssl_client_cert *cc)\n{\n    return &cc->cert;\n}\n\nconst char *ne_ssl_clicert_name(const ne_ssl_client_cert *ccert)\n{\n    return ccert->friendly_name;\n}\n\nne_ssl_certificate *ne_ssl_cert_read(const char *filename)\n{\n    int ret;\n    gnutls_datum_t data;\n    gnutls_x509_crt_t x5;\n\n    if (read_to_datum(filename, &data))\n        return NULL;\n\n    if (gnutls_x509_crt_init(&x5) != 0)\n        return NULL;\n\n    ret = gnutls_x509_crt_import(x5, &data, GNUTLS_X509_FMT_PEM);\n    ne_free(data.data);\n    if (ret < 0) {\n        gnutls_x509_crt_deinit(x5);\n        return NULL;\n    }\n    \n    return populate_cert(ne_calloc(sizeof(struct ne_ssl_certificate_s)), x5);\n}\n\nint ne_ssl_cert_write(const ne_ssl_certificate *cert, const char *filename)\n{\n    unsigned char buffer[10*1024];\n    size_t len = sizeof buffer;\n\n    FILE *fp = fopen(filename, \"w\");\n\n    if (fp == NULL) return -1;\n\n    if (gnutls_x509_crt_export(cert->subject, GNUTLS_X509_FMT_PEM, buffer,\n                               &len) < 0) {\n        fclose(fp);\n        return -1;\n    }\n\n    if (fwrite(buffer, len, 1, fp) != 1) {\n        fclose(fp);\n        return -1;\n    }\n\n    if (fclose(fp) != 0)\n        return -1;\n\n    return 0;\n}\n\nvoid ne_ssl_cert_free(ne_ssl_certificate *cert)\n{\n    gnutls_x509_crt_deinit(cert->subject);\n    if (cert->identity) ne_free(cert->identity);\n    if (cert->issuer) ne_ssl_cert_free(cert->issuer);\n    ne_free(cert);\n}\n\nint ne_ssl_cert_cmp(const ne_ssl_certificate *c1, const ne_ssl_certificate *c2)\n{\n#ifdef HAVE_GNUTLS_X509_CRT_EQUALS\n    return !gnutls_x509_crt_equals(c1->subject, c2->subject);\n#else\n    char digest1[NE_SSL_DIGESTLEN], digest2[NE_SSL_DIGESTLEN];\n\n    if (ne_ssl_cert_digest(c1, digest1) || ne_ssl_cert_digest(c2, digest2)) {\n        return -1;\n    }\n\n    return strcmp(digest1, digest2);\n#endif\n}\n\n/* The certificate import/export format is the base64 encoding of the\n * raw DER; PEM without the newlines and wrapping. */\n\nne_ssl_certificate *ne_ssl_cert_import(const char *data)\n{\n    int ret;\n    size_t len;\n    unsigned char *der;\n    gnutls_datum_t buffer = { NULL, 0 };\n    gnutls_x509_crt_t x5;\n\n    if (gnutls_x509_crt_init(&x5) != 0)\n        return NULL;\n\n    /* decode the base64 to get the raw DER representation */\n    len = ne_unbase64(data, &der);\n    if (len == 0) return NULL;\n\n    buffer.data = der;\n    buffer.size = len;\n\n    ret = gnutls_x509_crt_import(x5, &buffer, GNUTLS_X509_FMT_DER);\n    ne_free(der);\n\n    if (ret < 0) {\n        gnutls_x509_crt_deinit(x5);\n        return NULL;\n    }\n\n    return populate_cert(ne_calloc(sizeof(struct ne_ssl_certificate_s)), x5);\n}\n\nchar *ne_ssl_cert_export(const ne_ssl_certificate *cert)\n{\n    unsigned char *der;\n    size_t len = 0;\n    char *ret;\n\n    /* find the length of the DER encoding. */\n    if (gnutls_x509_crt_export(cert->subject, GNUTLS_X509_FMT_DER, NULL, &len) != \n        GNUTLS_E_SHORT_MEMORY_BUFFER) {\n        return NULL;\n    }\n    \n    der = ne_malloc(len);\n    if (gnutls_x509_crt_export(cert->subject, GNUTLS_X509_FMT_DER, der, &len)) {\n        ne_free(der);\n        return NULL;\n    }\n    \n    ret = ne_base64(der, len);\n    ne_free(der);\n    return ret;\n}\n\nstatic gnutls_digest_algorithm_t hash_to_alg(unsigned int flags)\n{\n    switch (flags & NE_HASH_ALGMASK) {\n    case NE_HASH_MD5: return GNUTLS_DIG_MD5; break;\n    case NE_HASH_SHA256: return GNUTLS_DIG_SHA256; break;\n    case NE_HASH_SHA512: return GNUTLS_DIG_SHA512; break;\n    case NE_HASH_SHA1: return GNUTLS_DIG_SHA1; break;\n    default: break;\n    }\n    return GNUTLS_DIG_UNKNOWN;\n}\n\nchar *ne_ssl_cert_hdigest(const ne_ssl_certificate *cert, unsigned int flags)\n{\n    gnutls_digest_algorithm_t alg = hash_to_alg(flags);\n    unsigned char *dig;\n    size_t len;\n    char *rv;\n\n    if (alg == GNUTLS_DIG_UNKNOWN) return NULL;\n\n    if (gnutls_x509_crt_get_fingerprint(cert->subject, alg, NULL, &len) != GNUTLS_E_SHORT_MEMORY_BUFFER) {\n        return NULL;\n    }\n\n    dig = ne_malloc(len);\n    if (gnutls_x509_crt_get_fingerprint(cert->subject, alg, dig, &len) < 0) {\n        ne_free(dig);\n        return NULL;\n    }\n\n    rv = ne__strhash2hex(dig, len, flags);\n    ne_free(dig);\n    return rv;\n}\n\nint ne_ssl_cert_digest(const ne_ssl_certificate *cert, char *digest)\n{\n    char sha1[20], *p;\n    int j;\n    size_t len = sizeof sha1;\n\n    if (gnutls_x509_crt_get_fingerprint(cert->subject, GNUTLS_DIG_SHA,\n                                        sha1, &len) < 0)\n        return -1;\n\n    for (j = 0, p = digest; j < 20; j++) {\n        *p++ = NE_HEX2ASC((sha1[j] >> 4) & 0x0f);\n        *p++ = NE_HEX2ASC(sha1[j] & 0x0f);\n        *p++ = ':';\n    }\n\n    *--p = '\\0';\n    return 0;\n}\n\nint ne__ssl_init(void)\n{\n#if LIBGNUTLS_VERSION_NUMBER < 0x020b01\n#ifdef NE_HAVE_TS_SSL\n    gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);\n#endif\n    gcry_control(GCRYCTL_ENABLE_QUICK_RANDOM, 0);\n#endif\n    return gnutls_global_init();\n}\n\nvoid ne__ssl_exit(void)\n{\n    /* No way to unregister the thread callbacks.  Doomed. */\n#if LIBGNUTLS_VERSION_MAJOR > 1 || LIBGNUTLS_VERSION_MINOR > 3 \\\n    || (LIBGNUTLS_VERSION_MINOR == 3 && LIBGNUTLS_VERSION_PATCH >= 3)\n    /* It's safe to call gnutls_global_deinit() here only with\n     * gnutls >= 1.3., since older versions don't refcount and\n     * doing so would prevent any other use of gnutls within\n     * the process. */\n    gnutls_global_deinit();\n#endif\n}\n\nchar *ne_vstrhash(unsigned int flags, va_list ap)\n{\n    gnutls_digest_algorithm_t alg = hash_to_alg(flags);\n    gnutls_hash_hd_t hd;\n    unsigned char *out;\n    const char *arg;\n    unsigned len;\n    char *rv;\n\n    if (alg == GNUTLS_DIG_UNKNOWN)\n        return NULL;\n\n    if (gnutls_hash_init(&hd, alg) < 0)\n        return NULL;\n\n    while ((arg = va_arg(ap, const char *)) != NULL)\n        gnutls_hash(hd, arg, strlen(arg));\n\n    len = gnutls_hash_get_len(alg);\n    out = ne_malloc(len);\n    gnutls_hash_deinit(hd, out);\n\n    rv = ne__strhash2hex(out, len, flags);\n    ne_free(out);\n    return rv;\n}\n\nint ne_mknonce(unsigned char *nonce, size_t len, unsigned int flags)\n{\n#if LIBGNUTLS_VERSION_NUMBER < 0x020b00\n    gcry_create_nonce(nonce, len);\n    return 0;\n#else\n    return gnutls_rnd(GNUTLS_RND_NONCE, nonce, len) == 0 ? 0 : EAGAIN;\n#endif\n}\n"
  },
  {
    "path": "src/ne_i18n.c",
    "content": "/* \n   Internationalization of neon\n   Copyright (C) 1999-2021, Joe Orton <joe@manyfish.co.uk>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n   \n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n\n#include \"config.h\"\n\n#include \"ne_i18n.h\"\n\n#ifdef HAVE_LIBINTL_H\n#include <libintl.h>\n#endif\n\nvoid ne_i18n_init(const char *encoding)\n{\n#if defined(NE_HAVE_I18N) && defined(NEON_IS_LIBRARY)\n    /* The bindtextdomain call is only enabled if neon is built as a\n     * library rather than as a bundled source; it would be possible\n     * in the future to allow it for bundled builds too, if the neon\n     * message catalogs could be installed alongside the app's own\n     * message catalogs. */\n    bindtextdomain(\"neon\", LOCALEDIR);\n\n#ifdef HAVE_BIND_TEXTDOMAIN_CODESET\n    if (encoding) {\n        bind_textdomain_codeset(\"neon\", encoding);\n    }\n#endif /* HAVE_BIND_TEXTDOMAIN_CODESET */\n\n#endif\n}\n"
  },
  {
    "path": "src/ne_i18n.h",
    "content": "/* \n   Internationalization of neon\n   Copyright (C) 2005-2021, Joe Orton <joe@manyfish.co.uk>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n   \n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n\n#ifndef NE_I18N_H\n#define NE_I18N_H\n\n#include \"ne_defs.h\"\n\nNE_BEGIN_DECLS\n\n/* Initialize translated error messages within neon.  If 'encoding' is\n * non-NULL, it specifies the character encoding for the generated\n * translated strings.  If it is NULL, the appropriate character\n * encoding for the locale will be used.\n *\n * This call is only strictly necessary if either:\n *\n * a) neon has been installed into a different prefix than the\n * gettext() implementation on which it depends for i18n purposes, or\n *\n * b) the caller requires that translated messages are in a particular\n * character encoding.\n *\n * If ne_i18n_init() is never called, the message catalogs will not be\n * found if case (a) applies (and so English error messages will be\n * used), and will use the default character encoding specified by the\n * process locale.  The library will otherwise operate correctly.\n *\n * Note that the encoding used is a process-global setting and so\n * results may be unexpected if other users of neon within the process\n * call ne_i18n_init() with a different encoding parameter.\n */\nvoid ne_i18n_init(const char *encoding);\n\nNE_END_DECLS\n\n#endif /* NE_I18N_H */\n"
  },
  {
    "path": "src/ne_internal.h",
    "content": "/* \n   Global interfaces private to neon.\n   Copyright (C) 2005-2021, Joe Orton <joe@manyfish.co.uk>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n   \n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n\n/* NOTE WELL: The interfaces defined in this file are internal to neon\n * and MUST NOT be used by neon-based applications. */\n\n#ifndef NE_INTERNAL_H\n#define NE_INTERNAL_H 1\n\n#include \"config.h\"\n\n#ifdef HAVE_SYS_LIMITS_H\n#include <sys/limits.h>\n#endif\n#ifdef HAVE_LIMITS_H\n#include <limits.h> /* for UINT_MAX etc */\n#endif\n\n#include \"ne_defs.h\"\n\n#undef _\n#ifdef NE_HAVE_I18N\n#include <libintl.h>\n#define _(str) dgettext(PACKAGE_NAME, str)\n#else\n#define _(str) (str)\n#endif /* NE_ENABLE_NLS */\n#define N_(str) (str)\n\n#if !defined(LONG_LONG_MAX) && defined(LLONG_MAX)\n#define LONG_LONG_MAX LLONG_MAX\n#elif !defined(LONG_LONG_MAX) && defined(LONGLONG_MAX)\n#define LONG_LONG_MAX LONGLONG_MAX\n#endif\n\n#if defined(NE_LFS)\n\n#define ne_lseek lseek64\n#define FMT_NE_OFF_T NE_FMT_OFF64_T\n#define NE_OFFT_MAX LONG_LONG_MAX\n#ifdef HAVE_STRTOLL\n#define ne_strtoff strtoll\n#else\n#define ne_strtoff strtoq\n#endif\n\n#else /* !NE_LFS */\n\n#define ne_lseek lseek\n#define FMT_NE_OFF_T NE_FMT_OFF_T\n\n#if defined(SIZEOF_LONG_LONG) && defined(LONG_LONG_MAX) \\\n    && SIZEOF_OFF_T == SIZEOF_LONG_LONG\n#define NE_OFFT_MAX LONG_LONG_MAX\n#else\n#define NE_OFFT_MAX LONG_MAX\n#endif\n\n#if SIZEOF_OFF_T > SIZEOF_LONG && defined(HAVE_STRTOLL)\n#define ne_strtoff strtoll\n#elif SIZEOF_OFF_T > SIZEOF_LONG && defined(HAVE_STRTOQ)\n#define ne_strtoff strtoq\n#else\n#define ne_strtoff strtol\n#endif\n#endif /* NE_LFS */\n\n#define NE_HASH_ALGMASK (0x000f)\n\n/* Return malloc-allocated ASCII hexadecimal representation of\n * input. */\nNE_PRIVATE char *ne__strhash2hex(const unsigned char *digest, size_t len, unsigned int flags);\n\n#ifdef HAVE_EXPLICIT_BZERO\n#define ne__strzero(s, n) explicit_bzero(s, n)\n#else\n#define ne__strzero(s, n) memset(s, 0, n)\n#endif\n\n#endif /* NE_INTERNAL_H */\n"
  },
  {
    "path": "src/ne_locks.c",
    "content": "/* \n   WebDAV Class 2 locking operations\n   Copyright (C) 1999-2021, Joe Orton <joe@manyfish.co.uk>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n   \n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n\n#include \"config.h\"\n\n#ifdef HAVE_STDLIB_H\n#include <stdlib.h>\n#endif\n\n#ifdef HAVE_STRING_H\n#include <string.h>\n#endif\n\n#ifdef HAVE_LIMITS_H\n#include <limits.h>\n#endif\n#ifdef HAVE_ERRNO_H\n#include <errno.h>\n#endif\n\n#include <assert.h>\n\n#include <ctype.h> /* for isdigit() */\n\n#include \"ne_alloc.h\"\n\n#include \"ne_request.h\"\n#include \"ne_xml.h\"\n#include \"ne_locks.h\"\n#include \"ne_uri.h\"\n#include \"ne_basic.h\"\n#include \"ne_props.h\"\n#include \"ne_207.h\"\n#include \"ne_internal.h\"\n#include \"ne_xmlreq.h\"\n\n#define HOOK_ID \"http://webdav.org/neon/hooks/webdav-locking\"\n\n/* A list of lock objects. */\nstruct lock_list {\n    struct ne_lock *lock;\n    struct lock_list *next, *prev;\n};\n\nstruct ne_lock_store_s {\n    struct lock_list *locks;\n    struct lock_list *cursor; /* current position in 'locks' */\n};\n\nstruct lh_req_cookie {\n    const ne_lock_store *store;\n    struct lock_list *submit;\n};\n\n/* Context for PROPFIND/lockdiscovery callbacks */\nstruct discover_ctx {\n    ne_propfind_handler *phandler;\n    ne_lock_result results;\n    void *userdata;\n    ne_buffer *cdata;\n};\n\n/* Context for handling LOCK response */\nstruct lock_ctx {\n    struct ne_lock active; /* activelock */\n    ne_request *req; /* the request in question */\n    ne_xml_parser *parser;\n    char *token; /* the token we're after. */\n    int found;\n    ne_buffer *cdata;\n};\n\n/* use the \"application\" state space. */\n#define ELM_LOCK_FIRST (NE_PROPS_STATE_TOP + 66)\n\n#define ELM_lockdiscovery (ELM_LOCK_FIRST)\n#define ELM_activelock (ELM_LOCK_FIRST + 1)\n#define ELM_lockscope (ELM_LOCK_FIRST + 2)\n#define ELM_locktype (ELM_LOCK_FIRST + 3)\n#define ELM_depth (ELM_LOCK_FIRST + 4)\n#define ELM_owner (ELM_LOCK_FIRST + 5)\n#define ELM_timeout (ELM_LOCK_FIRST + 6)\n#define ELM_locktoken (ELM_LOCK_FIRST + 7)\n#define ELM_lockinfo (ELM_LOCK_FIRST + 8)\n#define ELM_write (ELM_LOCK_FIRST + 9)\n#define ELM_exclusive (ELM_LOCK_FIRST + 10)\n#define ELM_shared (ELM_LOCK_FIRST + 11)\n#define ELM_href (ELM_LOCK_FIRST + 12)\n#define ELM_prop (NE_207_STATE_PROP)\n#define ELM_lockroot (ELM_LOCK_FIRST + 13)\n\nstatic const struct ne_xml_idmap element_map[] = {\n#define ELM(x) { \"DAV:\", #x, ELM_ ## x }\n    ELM(lockdiscovery), ELM(activelock), ELM(prop), ELM(lockscope),\n    ELM(locktype), ELM(depth), ELM(owner), ELM(timeout), ELM(locktoken),\n    ELM(lockinfo), ELM(lockscope), ELM(locktype), ELM(write), ELM(exclusive),\n    ELM(shared), ELM(href), ELM(lockroot)\n    /* no \"lockentry\" */\n#undef ELM\n};\n\nstatic const ne_propname lock_props[] = {\n    { \"DAV:\", \"lockdiscovery\" },\n    { NULL }\n};\n\n/* this simply registers the accessor for the function. */\nstatic void lk_create(ne_request *req, void *session, \n\t\t       const char *method, const char *uri)\n{\n    struct lh_req_cookie *lrc = ne_malloc(sizeof *lrc);\n    lrc->store = session;\n    lrc->submit = NULL;\n    ne_set_request_private(req, HOOK_ID, lrc);\n}\n\nstatic void lk_pre_send(ne_request *r, void *userdata, ne_buffer *req)\n{\n    struct lh_req_cookie *lrc = ne_get_request_private(r, HOOK_ID);\n\n    if (lrc->submit != NULL) {\n\tstruct lock_list *item;\n        int ntl = ne_get_session_flag(ne_get_session(r), NE_SESSFLAG_SHAREPOINT);\n\n        /* Sharepoint doesn't like the more-accurate tagged-list\n         * format for If: headers, so use the no-tag-list format iff\n         * the Sharepoint hacks flag is enabled.  See\n         * <https://tools.ietf.org/html/rfc4918#section-10.4.2> */\n        if (ntl)\n            NE_DEBUG(NE_DBG_LOCKS, \"lock: Using no-tag-list If: header construction\\n\");\n\n\t/* Add in the If header */\n        ne_buffer_zappend(req, ntl ? \"If: (\" : \"If:\");\n\n\tfor (item = lrc->submit; item != NULL; item = item->next) {\n            if (ntl) {\n                ne_buffer_concat(req, \"<\", item->lock->token, \">\",\n                                 item->next ? \" \" : \"\", NULL);\n            }\n            else {\n                char *uri = ne_uri_unparse(&item->lock->uri);\n                ne_buffer_concat(req, \" <\", uri, \"> (<\",\n                                 item->lock->token, \">)\", NULL);\n                ne_free(uri);\n            }\n\t}\n\n\tne_buffer_zappend(req, ntl ? \")\\r\\n\" : \"\\r\\n\");\n    }\n}\n\n/* Insert 'lock' into lock list *list. */\nstatic void insert_lock(struct lock_list **list, struct ne_lock *lock)\n{\n    struct lock_list *item = ne_malloc(sizeof *item);\n    if (*list != NULL) {\n\t(*list)->prev = item;\n    }\n    item->prev = NULL;\n    item->next = *list;\n    item->lock = lock;\n    *list = item;\n}\n\nstatic void free_list(struct lock_list *list, int destroy)\n{\n    struct lock_list *next;\n\n    while (list != NULL) {\n\tnext = list->next;\n\tif (destroy)\n\t    ne_lock_destroy(list->lock);\n\tne_free(list);\n\tlist = next;\n    }\n}\n\nstatic void lk_destroy(ne_request *req, void *userdata)\n{\n    struct lh_req_cookie *lrc = ne_get_request_private(req, HOOK_ID);\n    free_list(lrc->submit, 0);\n    ne_free(lrc);\n}\n\nvoid ne_lockstore_destroy(ne_lock_store *store)\n{\n    free_list(store->locks, 1);\n    ne_free(store);\n}\n\nne_lock_store *ne_lockstore_create(void)\n{\n    return ne_calloc(sizeof(ne_lock_store));\n}\n\n#define CURSOR_RET(s) ((s)->cursor?(s)->cursor->lock:NULL)\n\nstruct ne_lock *ne_lockstore_first(ne_lock_store *store)\n{\n    store->cursor = store->locks;\n    return CURSOR_RET(store);\n}\n\nstruct ne_lock *ne_lockstore_next(ne_lock_store *store)\n{\n    store->cursor = store->cursor->next;\n    return CURSOR_RET(store);\n}\n\nvoid ne_lockstore_register(ne_lock_store *store, ne_session *sess)\n{\n    /* Register the hooks */\n    ne_hook_create_request(sess, lk_create, store);\n    ne_hook_pre_send(sess, lk_pre_send, store);\n    ne_hook_destroy_request(sess, lk_destroy, store);\n}\n\n/* Submit the given lock for the given URI */\nstatic void submit_lock(struct lh_req_cookie *lrc, struct ne_lock *lock)\n{\n    struct lock_list *item;\n\n    /* Check for dups */\n    for (item = lrc->submit; item != NULL; item = item->next) {\n\tif (ne_strcasecmp(item->lock->token, lock->token) == 0)\n\t    return;\n    }\n\n    insert_lock(&lrc->submit, lock);\n}\n\nstruct ne_lock *ne_lockstore_findbyuri(ne_lock_store *store,\n\t\t\t\t       const ne_uri *uri)\n{\n    struct lock_list *cur;\n\n    for (cur = store->locks; cur != NULL; cur = cur->next) {\n\tif (ne_uri_cmp(&cur->lock->uri, uri) == 0) {\n\t    return cur->lock;\n\t}\n    }\n\n    return NULL;\n}\n\nvoid ne_lock_using_parent(ne_request *req, const char *path)\n{\n    struct lh_req_cookie *lrc = ne_get_request_private(req, HOOK_ID);\n    ne_uri u = {0};\n    struct lock_list *item;\n    char *parent;\n\n    if (lrc == NULL)\n\treturn;\n    \n    parent = ne_path_parent(path);\n    if (parent == NULL)\n\treturn;\n    \n    ne_fill_server_uri(ne_get_session(req), &u);\n\n    for (item = lrc->store->locks; item != NULL; item = item->next) {\n\n\t/* Only care about locks which are on this server. */\n\tu.path = item->lock->uri.path;\n\tif (ne_uri_cmp(&u, &item->lock->uri))\n\t    continue;\n\t\n\t/* This lock is needed if it is an infinite depth lock which\n\t * covers the parent, or a lock on the parent itself. */\n\tif ((item->lock->depth == NE_DEPTH_INFINITE && \n\t     ne_path_childof(item->lock->uri.path, parent)) ||\n\t    ne_path_compare(item->lock->uri.path, parent) == 0) {\n\t    NE_DEBUG(NE_DBG_LOCKS, \"Locked parent, %s on %s\\n\",\n\t\t     item->lock->token, item->lock->uri.path);\n\t    submit_lock(lrc, item->lock);\n\t}\n    }\n\n    u.path = parent; /* handy: makes u.path valid and ne_free(parent). */\n    ne_uri_free(&u);\n}\n\nvoid ne_lock_using_resource(ne_request *req, const char *uri, int depth)\n{\n    struct lh_req_cookie *lrc = ne_get_request_private(req, HOOK_ID);\n    struct lock_list *item;\n    int match;\n\n    if (lrc == NULL)\n\treturn;\t\n\n    /* Iterate over the list of stored locks to see if any of them\n     * apply to this resource */\n    for (item = lrc->store->locks; item != NULL; item = item->next) {\n\t\n\tmatch = 0;\n\t\n\tif (depth == NE_DEPTH_INFINITE &&\n\t    ne_path_childof(uri, item->lock->uri.path)) {\n\t    /* Case 1: this is a depth-infinity request which will \n\t     * modify a lock somewhere inside the collection. */\n\t    NE_DEBUG(NE_DBG_LOCKS, \"Has child: %s\\n\", item->lock->token);\n\t    match = 1;\n\t} \n\telse if (ne_path_compare(uri, item->lock->uri.path) == 0) {\n\t    /* Case 2: this request is directly on a locked resource */\n\t    NE_DEBUG(NE_DBG_LOCKS, \"Has direct lock: %s\\n\", item->lock->token);\n\t    match = 1;\n\t}\n\telse if (item->lock->depth == NE_DEPTH_INFINITE && \n\t\t ne_path_childof(item->lock->uri.path, uri)) {\n\t    /* Case 3: there is a higher-up infinite-depth lock which\n\t     * covers the resource that this request will modify. */\n\t    NE_DEBUG(NE_DBG_LOCKS, \"Is child of: %s\\n\", item->lock->token);\n\t    match = 1;\n\t}\n\t\n\tif (match) {\n\t    submit_lock(lrc, item->lock);\n\t}\n    }\n\n}\n\nvoid ne_lockstore_add(ne_lock_store *store, struct ne_lock *lock)\n{\n    insert_lock(&store->locks, lock);\n}\n\nvoid ne_lockstore_remove(ne_lock_store *store, struct ne_lock *lock)\n{\n    struct lock_list *item;\n\n    /* Find the lock */\n    for (item = store->locks; item != NULL; item = item->next)\n\tif (item->lock == lock)\n\t    break;\n\n    /* API condition that lock is present in the store. */\n    assert(item);\n    \n    if (item->prev != NULL) {\n\titem->prev->next = item->next;\n    } else {\n\tstore->locks = item->next;\n    }\n    if (item->next != NULL) {\n\titem->next->prev = item->prev;\n    }\n    ne_free(item);\n}\n\nstruct ne_lock *ne_lock_copy(const struct ne_lock *lock)\n{\n    struct ne_lock *ret = ne_calloc(sizeof *ret);\n\n    ne_uri_copy(&ret->uri, &lock->uri);\n    ret->token = ne_strdup(lock->token);\n    ret->depth = lock->depth;\n    ret->type = lock->type;\n    ret->scope = lock->scope;\n    if (lock->owner) ret->owner = ne_strdup(lock->owner);\n    ret->timeout = lock->timeout;\n\n    return ret;\n}\n\nstruct ne_lock *ne_lock_create(void)\n{\n    struct ne_lock *lock = ne_calloc(sizeof *lock);\n    lock->depth = NE_DEPTH_ZERO;\n    lock->type = ne_locktype_write;\n    lock->scope = ne_lockscope_exclusive;\n    lock->timeout = NE_TIMEOUT_INVALID;\n    return lock;\n}\n\nvoid ne_lock_free(struct ne_lock *lock)\n{\n    ne_uri_free(&lock->uri);\n    if (lock->owner) {\n        ne_free(lock->owner);\n        lock->owner = NULL;\n    }\n    if (lock->token) {\n        ne_free(lock->token);\n        lock->token = NULL;\n    }\n}\n\nvoid ne_lock_destroy(struct ne_lock *lock)\n{\n    ne_lock_free(lock);\n    ne_free(lock);\n}\n\nint ne_unlock(ne_session *sess, const struct ne_lock *lock)\n{\n    ne_request *req = ne_request_create(sess, \"UNLOCK\", lock->uri.path);\n    int ret;\n    \n    ne_print_request_header(req, \"Lock-Token\", \"<%s>\", lock->token);\n    \n    /* UNLOCK of a lock-null resource removes the resource from the\n     * parent collection; so an UNLOCK may modify the parent\n     * collection. (somewhat counter-intuitive, and not easily derived\n     * from 2518.) */\n    ne_lock_using_parent(req, lock->uri.path);\n\n    ret = ne_request_dispatch(req);\n    \n    if (ret == NE_OK && ne_get_status(req)->klass != 2) {\n\tret = NE_ERROR;\n    }\n\n    ne_request_destroy(req);\n    \n    return ret;\n}\n\nstatic int parse_depth(const char *depth)\n{\n    if (ne_strcasecmp(depth, \"infinity\") == 0) {\n\treturn NE_DEPTH_INFINITE;\n    } else if (isdigit(depth[0])) {\n\treturn atoi(depth);\n    } else {\n\treturn -1;\n    }\n}\n\nstatic long parse_timeout(const char *timeout)\n{\n    if (ne_strcasecmp(timeout, \"infinite\") == 0) {\n\treturn NE_TIMEOUT_INFINITE;\n    } else if (strncasecmp(timeout, \"Second-\", 7) == 0) {\n\tunsigned long ut;\n\n        /* The value for a lock timeout should be unsigned 32-bit per\n         * <http://tools.ietf.org/html/rfc4918#section-10.7> but the\n         * ne_lock API used a \"long\" timeout, so map anything bigger\n         * to LONG_MAX. */\n        errno = 0;\n        ut = strtoul(timeout+7, NULL, 10);\n        if (ut == ULONG_MAX && errno == ERANGE)\n            return NE_TIMEOUT_INVALID;\n\n        if (ut > LONG_MAX)\n            return LONG_MAX;\n        else\n            return (long)ut;\n    } else {\n\treturn NE_TIMEOUT_INVALID;\n    }\n}\n\nstatic void discover_results(void *userdata, const ne_uri *uri,\n\t\t\t     const ne_prop_result_set *set)\n{\n    struct discover_ctx *ctx = userdata;\n    struct ne_lock *lock = ne_propset_private(set);\n    const ne_status *status = ne_propset_status(set, &lock_props[0]);\n\n    /* Require at least that the lock has a token. */\n    if (lock->token) {\n\tif (status && status->klass != 2) {\n\t    ctx->results(ctx->userdata, NULL, uri, status);\n\t} else {\n\t    ctx->results(ctx->userdata, lock, uri, NULL);\n\t}\n    }\n    else if (status) {\n\tctx->results(ctx->userdata, NULL, uri, status);\n    }\n\n    NE_DEBUG(NE_DBG_LOCKS, \"End of response for %s\\n\", uri->path);\n}\n\nstatic int \nend_element_common(struct ne_lock *l, int state, const char *cdata)\n{\n    switch (state) { \n    case ELM_write:\n\tl->type = ne_locktype_write;\n\tbreak;\n    case ELM_exclusive:\n\tl->scope = ne_lockscope_exclusive;\n\tbreak;\n    case ELM_shared:\n\tl->scope = ne_lockscope_shared;\n\tbreak;\n    case ELM_depth:\n\tNE_DEBUG(NE_DBG_LOCKS, \"Got depth: %s\\n\", cdata);\n\tl->depth = parse_depth(cdata);\n\tif (l->depth == -1) {\n\t    return -1;\n\t}\n\tbreak;\n    case ELM_timeout:\n\tNE_DEBUG(NE_DBG_LOCKS, \"Got timeout: %s\\n\", cdata);\n\tl->timeout = parse_timeout(cdata);\n\tif (l->timeout == NE_TIMEOUT_INVALID) {\n\t    return -1;\n\t}\n\tbreak;\n    case ELM_owner:\n\tl->owner = strdup(cdata);\n\tbreak;\n    case ELM_locktoken:\n\tl->token = strdup(cdata);\n\tbreak;\n    case ELM_lockroot:\n        ne_uri_free(&l->uri);\n        if (ne_uri_parse(cdata, &l->uri)) {\n            NE_DEBUG(NE_DBG_LOCKS, \"lock: URI parse failed for %s\\n\", cdata);\n            return -1;\n        }\n\tbreak;\n    }\n    return 0;\n}\n\n/* End-element handler for lock discovery PROPFIND response */\nstatic int end_element_ldisc(void *userdata, int state, \n                             const char *nspace, const char *name)\n{\n    struct discover_ctx *ctx = userdata;\n    struct ne_lock *lock = ne_propfind_current_private(ctx->phandler);\n\n    return end_element_common(lock, state, ctx->cdata->data);\n}\n\nstatic inline int can_accept(int parent, int id)\n{\n    return (parent == NE_XML_STATEROOT && id == ELM_prop)\n        || (parent == ELM_prop && id == ELM_lockdiscovery)\n        || (parent == ELM_lockdiscovery && id == ELM_activelock)\n        || (parent == ELM_activelock\n            && (id == ELM_lockscope || id == ELM_locktype\n                || id == ELM_depth || id == ELM_owner\n                || id == ELM_timeout || id == ELM_locktoken\n                || id == ELM_lockroot))\n        || (parent == ELM_lockscope\n            && (id == ELM_exclusive || id == ELM_shared))\n        || (parent == ELM_locktype && id == ELM_write)\n        || (id == ELM_href\n            && (parent == ELM_locktoken || parent == ELM_lockroot));\n\n}\n\nstatic int ld_startelm(void *userdata, int parent,\n                       const char *nspace, const char *name,\n\t\t       const char **atts)\n{\n    struct discover_ctx *ctx = userdata;\n    int id = ne_xml_mapid(element_map, NE_XML_MAPLEN(element_map),\n                          nspace, name);\n    \n    ne_buffer_clear(ctx->cdata);\n    \n    if (can_accept(parent, id))\n        return id;\n    else\n        return NE_XML_DECLINE;\n}    \n\n#define MAX_CDATA (256)\n\nstatic int common_cdata(ne_buffer *buf, int state,\n                        const char *cdata, size_t len)\n{\n    switch (state) {\n    case ELM_depth:\n    case ELM_timeout:\n    case ELM_owner:\n    case ELM_href:\n        if (buf->used + len < MAX_CDATA)\n            ne_buffer_append(buf, cdata, len);\n        break;\n    }\n    \n    return 0;\n}\n\nstatic int ld_cdata(void *userdata, int state,\n                    const char *cdata, size_t len)\n{\n    struct discover_ctx *ctx = userdata;\n\n    return common_cdata(ctx->cdata, state, cdata, len);\n}\n\nstatic int lk_cdata(void *userdata, int state,\n                    const char *cdata, size_t len)\n{\n    struct lock_ctx *ctx = userdata;\n\n    return common_cdata(ctx->cdata, state, cdata, len);\n}\n\nstatic int lk_startelm(void *userdata, int parent,\n                       const char *nspace, const char *name,\n\t\t       const char **atts)\n{\n    struct lock_ctx *ctx = userdata;\n    int id;\n\n    id = ne_xml_mapid(element_map, NE_XML_MAPLEN(element_map), nspace, name);\n\n    NE_DEBUG(NE_DBG_LOCKS, \"lk_startelm: %s => %d\\n\", name, id);\n    \n    if (id == 0)\n        return NE_XML_DECLINE;    \n\n    if (parent == 0 && ctx->token == NULL) {\n        const char *token = ne_get_response_header(ctx->req, \"Lock-Token\");\n        /* at the root element; retrieve the Lock-Token header,\n         * and bail if it wasn't given. */\n        if (token == NULL) {\n            ne_xml_set_error(ctx->parser, \n                             _(\"LOCK response missing Lock-Token header\"));\n            return NE_XML_ABORT;\n        }\n\n        if (token[0] == '<') token++;\n        ctx->token = ne_strdup(token);\n        ne_shave(ctx->token, \">\");\n        NE_DEBUG(NE_DBG_LOCKS, \"lk_startelm: Finding token %s\\n\",\n                 ctx->token);\n    }\n\n    /* TODO: only accept 'prop' as root for LOCK response */\n    if (!can_accept(parent, id))\n        return NE_XML_DECLINE;\n\n    if (id == ELM_activelock && !ctx->found) {\n\t/* a new activelock */\n\tne_lock_free(&ctx->active);\n\tmemset(&ctx->active, 0, sizeof ctx->active);\n        ctx->active.timeout = NE_TIMEOUT_INVALID;\n    }\n\n    ne_buffer_clear(ctx->cdata);\n\n    return id;\n}\n\n/* End-element handler for LOCK response */\nstatic int lk_endelm(void *userdata, int state,\n                     const char *nspace, const char *name)\n{\n    struct lock_ctx *ctx = userdata;\n\n    if (ctx->found)\n\treturn 0;\n\n    if (end_element_common(&ctx->active, state, ctx->cdata->data))\n\treturn -1;\n\n    if (state == ELM_activelock) {\n\tif (ctx->active.token && strcmp(ctx->active.token, ctx->token) == 0) {\n\t    ctx->found = 1;\n\t}\n    }\n\n    return 0;\n}\n\n/* Creator callback for private structure. */\nstatic void *ld_create(void *userdata, const ne_uri *uri)\n{\n    struct ne_lock *lk = ne_lock_create();\n\n    ne_uri_copy(&lk->uri, uri);\n\n    return lk;\n}\n\n/* Destructor callback for private structure. */\nstatic void ld_destroy(void *userdata, void *private)\n{\n    struct ne_lock *lk = private;\n\n    ne_lock_destroy(lk);\n}\n\n/* Discover all locks on URI */\nint ne_lock_discover(ne_session *sess, const char *uri, \n\t\t     ne_lock_result callback, void *userdata)\n{\n    ne_propfind_handler *handler;\n    struct discover_ctx ctx = {0};\n    int ret;\n    \n    ctx.results = callback;\n    ctx.userdata = userdata;\n    ctx.cdata = ne_buffer_create();\n    ctx.phandler = handler = ne_propfind_create(sess, uri, NE_DEPTH_ZERO);\n\n    ne_propfind_set_private(handler, ld_create, ld_destroy, &ctx);\n    \n    ne_xml_push_handler(ne_propfind_get_parser(handler), \n                        ld_startelm, ld_cdata, end_element_ldisc, &ctx);\n    \n    ret = ne_propfind_named(handler, lock_props, discover_results, &ctx);\n    \n    ne_buffer_destroy(ctx.cdata);\n    ne_propfind_destroy(handler);\n\n    return ret;\n}\n\nstatic void add_timeout_header(ne_request *req, long timeout)\n{\n    if (timeout == NE_TIMEOUT_INFINITE) {\n\tne_add_request_header(req, \"Timeout\", \"Infinite\");\n    } \n    else if (timeout != NE_TIMEOUT_INVALID && timeout > 0) {\n\tne_print_request_header(req, \"Timeout\", \"Second-%ld\", timeout);\n    }\n    /* just ignore it if timeout == 0 or invalid. */\n}\n\nint ne_lock(ne_session *sess, struct ne_lock *lock) \n{\n    ne_request *req = ne_request_create(sess, \"LOCK\", lock->uri.path);\n    ne_buffer *body = ne_buffer_create();\n    ne_xml_parser *parser = ne_xml_create();\n    int ret;\n    struct lock_ctx ctx;\n\n    memset(&ctx, 0, sizeof ctx);\n    ctx.cdata = ne_buffer_create();    \n    ctx.req = req;\n    ctx.parser = parser;\n\n    /* LOCK is not idempotent. */\n    ne_set_request_flag(req, NE_REQFLAG_IDEMPOTENT, 0);\n\n    ne_xml_push_handler(parser, lk_startelm, lk_cdata, lk_endelm, &ctx);\n    \n    /* Create the body */\n    ne_buffer_concat(body, \"<?xml version=\\\"1.0\\\" encoding=\\\"utf-8\\\"?>\\n\"\n\t\t    \"<lockinfo xmlns='DAV:'>\\n\" \" <lockscope>\",\n\t\t    lock->scope==ne_lockscope_exclusive?\n\t\t    \"<exclusive/>\":\"<shared/>\",\n\t\t    \"</lockscope>\\n\"\n\t\t    \"<locktype><write/></locktype>\", NULL);\n\n    if (lock->owner) {\n\tne_buffer_concat(body, \"<owner>\", lock->owner, \"</owner>\\n\", NULL);\n    }\n    ne_buffer_czappend(body, \"</lockinfo>\\n\");\n\n    ne_set_request_body_buffer(req, body->data, ne_buffer_size(body));\n    ne_add_request_header(req, \"Content-Type\", NE_XML_MEDIA_TYPE);\n    ne_add_depth_header(req, lock->depth);\n    add_timeout_header(req, lock->timeout);\n    \n    /* TODO: \n     * By 2518, we need this only if we are creating a lock-null resource.\n     * Since we don't KNOW whether the lock we're given is a lock-null\n     * or not, we cover our bases.\n     */\n    ne_lock_using_parent(req, lock->uri.path);\n    /* This one is clearer from 2518 sec 8.10.4. */\n    ne_lock_using_resource(req, lock->uri.path, lock->depth);\n\n    ret = ne_xml_dispatch_request(req, parser);\n\n    ne_buffer_destroy(body);\n    ne_buffer_destroy(ctx.cdata);\n    \n    if (ret == NE_OK && ne_get_status(req)->klass == 2) {\n        if (ne_get_status(req)->code == 207) {\n            ret = NE_ERROR;\n            /* TODO: set the error string appropriately */\n        } else if (ctx.found) {\n\t    /* it worked: copy over real lock details if given. */\n            if (lock->token) ne_free(lock->token);\n\t    lock->token = ctx.token;\n            ctx.token = NULL;\n\t    if (ctx.active.timeout != NE_TIMEOUT_INVALID)\n\t\tlock->timeout = ctx.active.timeout;\n\t    lock->scope = ctx.active.scope;\n\t    lock->type = ctx.active.type;\n\t    if (ctx.active.depth >= 0)\n\t\tlock->depth = ctx.active.depth;\n\t    if (ctx.active.owner) {\n\t\tif (lock->owner) ne_free(lock->owner);\n\t\tlock->owner = ctx.active.owner;\n\t\tctx.active.owner = NULL;\n\t    }\n\t} else {\n\t    ret = NE_ERROR;\n\t    ne_set_error(sess, _(\"Response missing activelock for %s\"), \n\t\t\t ctx.token);\n\t}\n    } else if (ret == NE_OK /* && status != 2xx */) {\n\tret = NE_ERROR;\n    }\n\n    ne_lock_free(&ctx.active);\n    if (ctx.token) ne_free(ctx.token);\n    ne_request_destroy(req);\n    ne_xml_destroy(parser);\n\n    return ret;\n}\n\nint ne_lock_refresh(ne_session *sess, struct ne_lock *lock)\n{\n    ne_request *req = ne_request_create(sess, \"LOCK\", lock->uri.path);\n    ne_xml_parser *parser = ne_xml_create();\n    int ret;\n    struct lock_ctx ctx;\n\n    memset(&ctx, 0, sizeof ctx);\n    ctx.cdata = ne_buffer_create();\n    ctx.req = req;\n    ctx.token = lock->token;\n    ctx.parser = parser;\n\n    /* Handle the response and update *lock appropriately. */\n    ne_xml_push_handler(parser, lk_startelm, lk_cdata, lk_endelm, &ctx);\n    \n    /* For a lock refresh, submitting only this lock token must be\n     * sufficient. */\n    ne_print_request_header(req, \"If\", \"(<%s>)\", lock->token);\n    add_timeout_header(req, lock->timeout);\n\n    /* LOCK is not idempotent. */\n    ne_set_request_flag(req, NE_REQFLAG_IDEMPOTENT, 0);\n\n    ret = ne_xml_dispatch_request(req, parser);\n\n    if (ret == NE_OK) {\n        if (ne_get_status(req)->klass != 2) {\n            ret = NE_ERROR; /* and use default session error */\n\t} else if (!ctx.found) {\n            ne_set_error(sess, _(\"No activelock for <%s> returned in \"\n                                 \"LOCK refresh response\"), lock->token);\n            ret = NE_ERROR;\n        } else /* success! */ {\n            /* update timeout for passed-in lock structure. */\n            lock->timeout = ctx.active.timeout;\n        }\n    }\n\n    ne_lock_free(&ctx.active);\n    ne_buffer_destroy(ctx.cdata);\n    ne_request_destroy(req);\n    ne_xml_destroy(parser);\n\n    return ret;\n}\n"
  },
  {
    "path": "src/ne_locks.h",
    "content": "/* \n   WebDAV Class 2 locking operations\n   Copyright (C) 1999-2021, Joe Orton <joe@manyfish.co.uk>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n   \n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n\n#ifndef NE_LOCKS_H\n#define NE_LOCKS_H\n\n#include \"ne_request.h\" /* for ne_session + ne_request */\n#include \"ne_uri.h\" /* for ne_uri */\n\nNE_BEGIN_DECLS\n\n/* The scope of a lock */\nenum ne_lock_scope {\n    ne_lockscope_exclusive,\n    ne_lockscope_shared\n};\n\n/* Lock type. Only write locks are defined in RFC2518. */\nenum ne_lock_type {\n    ne_locktype_write\n};\n\n/* A lock object. */\nstruct ne_lock {\n    ne_uri uri;\n    int depth; /* the depth of the lock (NE_DEPTH_*). */\n    enum ne_lock_type type;\n    enum ne_lock_scope scope;\n    char *token; /* the lock token: uniquely identifies this lock. */\n    char *owner; /* string describing the owner of the lock. */\n    long timeout; /* timeout in seconds. (or NE_TIMEOUT_*) */\n};\n/* NB: struct ne_lock Would be typedef'ed to ne_lock except lock is\n * a verb and a noun, so we already have ne_lock the function. Damn\n * the English language. */\n\n#define NE_TIMEOUT_INFINITE -1\n#define NE_TIMEOUT_INVALID -2\n\n/* Create a depth zero, exclusive write lock, with default timeout\n * (allowing a server to pick a default).  token, owner and uri are\n * unset. */\nstruct ne_lock *ne_lock_create(void);\n\n/* HINT: to initialize uri host/port/scheme for the lock's URI, use\n * ne_fill_server_uri from ne_session.h. */\n\n/* Deep-copy a lock structure: strdup's any of path, token, owner,\n * hostport which are set. */\nstruct ne_lock *ne_lock_copy(const struct ne_lock *lock);\n\n/* Free a lock structure; free's any of any of the URI, token and\n * owner which are set, but not the lock object itself. */\nvoid ne_lock_free(struct ne_lock *lock);\n\n/* Like ne_lock_free; but free's the lock object itself too. */\nvoid ne_lock_destroy(struct ne_lock *lock);\n\n/* ne_lock_store: an opaque type which is used to store a set of lock\n * objects. */\ntypedef struct ne_lock_store_s ne_lock_store;\n\n/* Create a lock store. */\nne_lock_store *ne_lockstore_create(void);\n\n/* Register the lock store 'store' with the HTTP session 'sess': any\n * operations made using 'sess' which operate on a locked resource,\n * can use the locks from 'store' if needed. */\nvoid ne_lockstore_register(ne_lock_store *store, ne_session *sess);\n\n/* Destroy a lock store, free'ing any locks remaining inside. */\nvoid ne_lockstore_destroy(ne_lock_store *store);\n\n/* Add a lock to the store: the store then \"owns\" the lock object, and\n * you must not free it. The lock MUST have all of:\n *  - a completed URI structure: scheme, host, port, and path all set\n *  - a valid lock token\n *  - a valid depth\n */\nvoid ne_lockstore_add(ne_lock_store *store, struct ne_lock *lock);\n\n/* Remove given lock object from store: 'lock' MUST point to a lock\n * object which is known to be in the store. */\nvoid ne_lockstore_remove(ne_lock_store *store, struct ne_lock *lock);\n\n/* Returns the first lock in the lock store, or NULL if the store is\n * empty. */\nstruct ne_lock *ne_lockstore_first(ne_lock_store *store);\n\n/* After ne_lockstore_first has been called; returns the next lock in\n * the lock store, or NULL if there are no more locks stored.\n * Behaviour is undefined if ne_lockstore_first has not been called on\n * 'store' since the store was created, or the last time this function\n * returned NULL for the store.. */\nstruct ne_lock *ne_lockstore_next(ne_lock_store *store);\n\n/* Find a lock in the store for the given server, and with the given\n * path. */\nstruct ne_lock *ne_lockstore_findbyuri(ne_lock_store *store, \n\t\t\t\t       const ne_uri *uri);\n\n/* Issue a LOCK request for the given lock.  Requires that the uri,\n * depth, type, scope, and timeout members of 'lock' are filled in.\n * owner and token must be malloc-allocated if not NULL; and may be\n * free()d by this function.  On successful return, lock->token will\n * contain the lock token. */\nint ne_lock(ne_session *sess, struct ne_lock *lock);\n\n/* Issue an UNLOCK request for the given lock */\nint ne_unlock(ne_session *sess, const struct ne_lock *lock);\n\n/* Refresh a lock; returns an NE_* code.  If lock->timeout is non-zero\n * on entry, the server is requested to update the lock timeout to the\n * given value (per RFC4918§7.7, servers MAY ignore the requested\n * timeout).  On success, lock->timeout is updated to the new timeout\n * given by the server. */\nint ne_lock_refresh(ne_session *sess, struct ne_lock *lock);\n\n/* Callback for lock discovery.  If 'lock' is NULL, something went\n * wrong performing lockdiscovery for the resource, look at 'status'\n * for the details. 'uri' is the URI against which lock discovery is\n * being performed, which may be different from the URI of a\n * discovered lock (lock->uri).\n * \n * If lock is non-NULL, at least lock->uri and lock->token will be\n * filled in; and status will be NULL. */\ntypedef void (*ne_lock_result)(void *userdata, const struct ne_lock *lock, \n\t\t\t       const ne_uri *uri, const ne_status *status);\n\n/* Perform lock discovery on the given path.  'result' is called with\n * the results (possibly >1 times).  */\nint ne_lock_discover(ne_session *sess, const char *path,\n\t\t     ne_lock_result result, void *userdata);\n\n/* The ne_lock_using_* functions should be used before dispatching a\n * request which modify resources.  If a lock store has been\n * registered with the session associated with the request, and locks\n * are present in the lock store which cover the resources which are\n * being modified by the request, then the appropriate lock tokens are\n * submitted in the request headers. */\n\n/* Indicate that request 'req' will modify the resource at 'path', and\n * is an operation of given 'depth'. */\nvoid ne_lock_using_resource(ne_request *req, const char *path, int depth);\n\n/* Indicate that request 'req' will modify the parent collection of\n * the resource found at 'path' (for instance when removing the\n * resource from the collection). */\nvoid ne_lock_using_parent(ne_request *req, const char *path);\n\nNE_END_DECLS\n\n#endif /* NE_LOCKS_H */\n"
  },
  {
    "path": "src/ne_md5.c",
    "content": "/* md5.c - Functions to compute MD5 message digest of files or memory blocks\n   according to the definition of MD5 in RFC 1321 from April 1992.\n   Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.\n   This file is part of the GNU C Library.\n\n   The GNU C Library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public License as\n   published by the Free Software Foundation; either version 2 of the\n   License, or (at your option) any later version.\n\n   The GNU C Library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with the GNU C Library; see the file COPYING.LIB.  If not,\n   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,\n   Boston, MA 02111-1307, USA.  */\n\n/* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.  */\n\n#include \"config.h\"\n\n#include <sys/types.h>\n\n#include <stdlib.h>\n#include <string.h>\n#ifdef HAVE_LIMITS_H\n# include <limits.h>\n#endif\n\n#ifdef HAVE_OPENSSL\n#include <openssl/opensslv.h>\n#include <openssl/md5.h>\n\n#if OPENSSL_VERSION_NUMBER >= 0x10101000\n#define HAVE_OPENSSL_EVP 1\n#include <openssl/evp.h>\n#endif\n\n#endif /* HAVE_OPENSSL */\n\n#include \"ne_md5.h\"\n#include \"ne_string.h\" /* for NE_ASC2HEX */\n\n#if SIZEOF_INT == 4\ntypedef unsigned int md5_uint32;\n#elif SIZEOF_LONG == 4\ntypedef unsigned long md5_uint32;\n#else\n# error \"Cannot determine unsigned 32-bit data type.\"\n#endif\n\n#define md5_process_block ne_md5_process_block\n#define md5_process_bytes ne_md5_process_bytes\n#define md5_finish_ctx ne_md5_finish_ctx\n#define md5_read_ctx ne_md5_read_ctx\n#define md5_stream ne_md5_stream\n#define md5_ctx ne_md5_ctx\n\n\n#ifdef WORDS_BIGENDIAN\n# define SWAP(n)\t\t\t\t\t\t\t\\\n    (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24))\n#else\n# define SWAP(n) (n)\n#endif\n\n/* Structure to save state of computation between the single steps.  */\nstruct md5_ctx\n{\n#ifdef HAVE_OPENSSL_EVP\n  EVP_MD_CTX *ctx;\n#elif defined(HAVE_OPENSSL)\n  MD5_CTX ctx;\n#else\n  md5_uint32 A;\n  md5_uint32 B;\n  md5_uint32 C;\n  md5_uint32 D;\n\n  md5_uint32 total[2];\n  md5_uint32 buflen;\n  char buffer[128];\n#endif\n};\n\n#ifndef HAVE_OPENSSL\n/* This array contains the bytes used to pad the buffer to the next\n   64-byte boundary.  (RFC 1321, 3.1: Step 1)  */\nstatic const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ...  */ };\n\n\n/* Initialize structure containing state of computation.\n   (RFC 1321, 3.3: Step 3)  */\nstatic void \nmd5_init_ctx (struct md5_ctx *ctx)\n{\n  ctx->A = 0x67452301;\n  ctx->B = 0xefcdab89;\n  ctx->C = 0x98badcfe;\n  ctx->D = 0x10325476;\n\n  ctx->total[0] = ctx->total[1] = 0;\n  ctx->buflen = 0;\n}\n\nstruct ne_md5_ctx *\nne_md5_create_ctx(void)\n{\n  struct md5_ctx *ctx = ne_malloc(sizeof *ctx);\n  md5_init_ctx(ctx);\n  return ctx;\n}\n\nextern void \nne_md5_reset_ctx(struct ne_md5_ctx *ctx)\n{\n  md5_init_ctx(ctx);\n}\n\nstruct ne_md5_ctx *\nne_md5_dup_ctx(struct ne_md5_ctx *ctx)\n{\n  return memcpy(ne_malloc(sizeof *ctx), ctx, sizeof *ctx);\n}\n\nvoid\nne_md5_destroy_ctx(struct ne_md5_ctx *ctx)\n{\n  ne_free(ctx);\n}\n\n/* Process the remaining bytes in the internal buffer and the usual\n   prolog according to the standard and write the result to RESBUF.\n\n   IMPORTANT: On some systems it is required that RESBUF is correctly\n   aligned for a 32 bits value.  */\nvoid *\nmd5_finish_ctx (struct md5_ctx *ctx, void *resbuf)\n{\n  /* Take yet unprocessed bytes into account.  */\n  md5_uint32 bytes = ctx->buflen;\n  md5_uint32 swap_bytes;\n  size_t pad;\n\n  /* Now count remaining bytes.  */\n  ctx->total[0] += bytes;\n  if (ctx->total[0] < bytes)\n    ++ctx->total[1];\n\n  pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes;\n  memcpy (&ctx->buffer[bytes], fillbuf, pad);\n\n  /* Put the 64-bit file length in *bits* at the end of the buffer.\n     Use memcpy to avoid aliasing problems.  On most systems, this\n     will be optimized away to the same code.  */\n  swap_bytes = SWAP (ctx->total[0] << 3);\n  memcpy (&ctx->buffer[bytes + pad], &swap_bytes, sizeof (swap_bytes));\n  swap_bytes = SWAP ((ctx->total[1] << 3) | (ctx->total[0] >> 29));\n  memcpy (&ctx->buffer[bytes + pad + 4], &swap_bytes, sizeof (swap_bytes));\n\n  /* Process last bytes.  */\n  md5_process_block (ctx->buffer, bytes + pad + 8, ctx);\n\n  return md5_read_ctx (ctx, resbuf);\n}\n\nvoid\nmd5_process_bytes (const void *buffer, size_t len, struct md5_ctx *ctx)\n{\n  /* When we already have some bits in our internal buffer concatenate\n     both inputs first.  */\n  if (ctx->buflen != 0)\n    {\n      size_t left_over = ctx->buflen;\n      size_t add = 128 - left_over > len ? len : 128 - left_over;\n\n      memcpy (&ctx->buffer[left_over], buffer, add);\n      ctx->buflen += add;\n\n      if (left_over + add > 64)\n\t{\n\t  md5_process_block (ctx->buffer, (left_over + add) & ~63, ctx);\n\t  /* The regions in the following copy operation cannot overlap.  */\n\t  memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~63],\n\t\t  (left_over + add) & 63);\n\t  ctx->buflen = (left_over + add) & 63;\n\t}\n\n      buffer = (const char *) buffer + add;\n      len -= add;\n    }\n\n  /* Process available complete blocks.  */\n  if (len > 64)\n    {\n      md5_process_block (buffer, len & ~63, ctx);\n      buffer = (const char *) buffer + (len & ~63);\n      len &= 63;\n    }\n\n  /* Move remaining bytes in internal buffer.  */\n  if (len > 0)\n    {\n      memcpy (ctx->buffer, buffer, len);\n      ctx->buflen = len;\n    }\n}\n\n\n/* These are the four functions used in the four steps of the MD5 algorithm\n   and defined in the RFC 1321.  The first function is a little bit optimized\n   (as found in Colin Plumbs public domain implementation).  */\n/* #define FF(b, c, d) ((b & c) | (~b & d)) */\n#define FF(b, c, d) (d ^ (b & (c ^ d)))\n#define FG(b, c, d) FF (d, b, c)\n#define FH(b, c, d) (b ^ c ^ d)\n#define FI(b, c, d) (c ^ (b | ~d))\n\n/* Process LEN bytes of BUFFER, accumulating context into CTX.\n   It is assumed that LEN % 64 == 0.  */\n\nvoid\nmd5_process_block (const void *buffer, size_t len, struct md5_ctx *ctx)\n{\n  md5_uint32 correct_words[16];\n  const unsigned char *words = buffer;\n  const unsigned char *endp = words + len;\n  md5_uint32 A = ctx->A;\n  md5_uint32 B = ctx->B;\n  md5_uint32 C = ctx->C;\n  md5_uint32 D = ctx->D;\n\n  /* First increment the byte count.  RFC 1321 specifies the possible\n     length of the file up to 2^64 bits.  Here we only compute the\n     number of bytes.  Do a double word increment.  */\n  ctx->total[0] += len;\n  if (ctx->total[0] < len)\n    ++ctx->total[1];\n\n  /* Process all bytes in the buffer with 64 bytes in each round of\n     the loop.  */\n  while (words < endp)\n    {\n      md5_uint32 *cwp = correct_words;\n      md5_uint32 A_save = A;\n      md5_uint32 B_save = B;\n      md5_uint32 C_save = C;\n      md5_uint32 D_save = D;\n\n      /* First round: using the given function, the context and a constant\n\t the next context is computed.  Because the algorithms processing\n\t unit is a 32-bit word and it is determined to work on words in\n\t little endian byte order we perhaps have to change the byte order\n\t before the computation.  To reduce the work for the next steps\n\t we store the swapped words in the array CORRECT_WORDS.  */\n\n#define OP(a, b, c, d, s, T)\t\t\t\t\t\t\\\n      do\t\t\t\t\t\t\t\t\\\n        {\t\t\t\t\t\t\t\t\\\n\t  md5_uint32 WORD_ = (md5_uint32)words[0] | ((md5_uint32)words[1] << 8) \\\n\t       | ((md5_uint32)words[2] << 16) | ((md5_uint32)words[3] << 24); \\\n\t  a += FF (b, c, d) + (*cwp++ = WORD_) + T;\t\t\\\n\t  words += 4;\t\t\t\t\t\t\t\\\n\t  CYCLIC (a, s);\t\t\t\t\t\t\\\n\t  a += b;\t\t\t\t\t\t\t\\\n        }\t\t\t\t\t\t\t\t\\\n      while (0)\n\n      /* It is unfortunate that C does not provide an operator for\n\t cyclic rotation.  Hope the C compiler is smart enough.  */\n#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))\n\n      /* Before we start, one word to the strange constants.\n\t They are defined in RFC 1321 as\n\n\t T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64\n       */\n\n      /* Round 1.  */\n      OP (A, B, C, D,  7, 0xd76aa478);\n      OP (D, A, B, C, 12, 0xe8c7b756);\n      OP (C, D, A, B, 17, 0x242070db);\n      OP (B, C, D, A, 22, 0xc1bdceee);\n      OP (A, B, C, D,  7, 0xf57c0faf);\n      OP (D, A, B, C, 12, 0x4787c62a);\n      OP (C, D, A, B, 17, 0xa8304613);\n      OP (B, C, D, A, 22, 0xfd469501);\n      OP (A, B, C, D,  7, 0x698098d8);\n      OP (D, A, B, C, 12, 0x8b44f7af);\n      OP (C, D, A, B, 17, 0xffff5bb1);\n      OP (B, C, D, A, 22, 0x895cd7be);\n      OP (A, B, C, D,  7, 0x6b901122);\n      OP (D, A, B, C, 12, 0xfd987193);\n      OP (C, D, A, B, 17, 0xa679438e);\n      OP (B, C, D, A, 22, 0x49b40821);\n\n      /* For the second to fourth round we have the possibly swapped words\n\t in CORRECT_WORDS.  Redefine the macro to take an additional first\n\t argument specifying the function to use.  */\n#undef OP\n#define OP(f, a, b, c, d, k, s, T)\t\t\t\t\t\\\n      do \t\t\t\t\t\t\t\t\\\n\t{\t\t\t\t\t\t\t\t\\\n\t  a += f (b, c, d) + correct_words[k] + T;\t\t\t\\\n\t  CYCLIC (a, s);\t\t\t\t\t\t\\\n\t  a += b;\t\t\t\t\t\t\t\\\n\t}\t\t\t\t\t\t\t\t\\\n      while (0)\n\n      /* Round 2.  */\n      OP (FG, A, B, C, D,  1,  5, 0xf61e2562);\n      OP (FG, D, A, B, C,  6,  9, 0xc040b340);\n      OP (FG, C, D, A, B, 11, 14, 0x265e5a51);\n      OP (FG, B, C, D, A,  0, 20, 0xe9b6c7aa);\n      OP (FG, A, B, C, D,  5,  5, 0xd62f105d);\n      OP (FG, D, A, B, C, 10,  9, 0x02441453);\n      OP (FG, C, D, A, B, 15, 14, 0xd8a1e681);\n      OP (FG, B, C, D, A,  4, 20, 0xe7d3fbc8);\n      OP (FG, A, B, C, D,  9,  5, 0x21e1cde6);\n      OP (FG, D, A, B, C, 14,  9, 0xc33707d6);\n      OP (FG, C, D, A, B,  3, 14, 0xf4d50d87);\n      OP (FG, B, C, D, A,  8, 20, 0x455a14ed);\n      OP (FG, A, B, C, D, 13,  5, 0xa9e3e905);\n      OP (FG, D, A, B, C,  2,  9, 0xfcefa3f8);\n      OP (FG, C, D, A, B,  7, 14, 0x676f02d9);\n      OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a);\n\n      /* Round 3.  */\n      OP (FH, A, B, C, D,  5,  4, 0xfffa3942);\n      OP (FH, D, A, B, C,  8, 11, 0x8771f681);\n      OP (FH, C, D, A, B, 11, 16, 0x6d9d6122);\n      OP (FH, B, C, D, A, 14, 23, 0xfde5380c);\n      OP (FH, A, B, C, D,  1,  4, 0xa4beea44);\n      OP (FH, D, A, B, C,  4, 11, 0x4bdecfa9);\n      OP (FH, C, D, A, B,  7, 16, 0xf6bb4b60);\n      OP (FH, B, C, D, A, 10, 23, 0xbebfbc70);\n      OP (FH, A, B, C, D, 13,  4, 0x289b7ec6);\n      OP (FH, D, A, B, C,  0, 11, 0xeaa127fa);\n      OP (FH, C, D, A, B,  3, 16, 0xd4ef3085);\n      OP (FH, B, C, D, A,  6, 23, 0x04881d05);\n      OP (FH, A, B, C, D,  9,  4, 0xd9d4d039);\n      OP (FH, D, A, B, C, 12, 11, 0xe6db99e5);\n      OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8);\n      OP (FH, B, C, D, A,  2, 23, 0xc4ac5665);\n\n      /* Round 4.  */\n      OP (FI, A, B, C, D,  0,  6, 0xf4292244);\n      OP (FI, D, A, B, C,  7, 10, 0x432aff97);\n      OP (FI, C, D, A, B, 14, 15, 0xab9423a7);\n      OP (FI, B, C, D, A,  5, 21, 0xfc93a039);\n      OP (FI, A, B, C, D, 12,  6, 0x655b59c3);\n      OP (FI, D, A, B, C,  3, 10, 0x8f0ccc92);\n      OP (FI, C, D, A, B, 10, 15, 0xffeff47d);\n      OP (FI, B, C, D, A,  1, 21, 0x85845dd1);\n      OP (FI, A, B, C, D,  8,  6, 0x6fa87e4f);\n      OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0);\n      OP (FI, C, D, A, B,  6, 15, 0xa3014314);\n      OP (FI, B, C, D, A, 13, 21, 0x4e0811a1);\n      OP (FI, A, B, C, D,  4,  6, 0xf7537e82);\n      OP (FI, D, A, B, C, 11, 10, 0xbd3af235);\n      OP (FI, C, D, A, B,  2, 15, 0x2ad7d2bb);\n      OP (FI, B, C, D, A,  9, 21, 0xeb86d391);\n\n      /* Add the starting values of the context.  */\n      A += A_save;\n      B += B_save;\n      C += C_save;\n      D += D_save;\n    }\n\n  /* Put checksum in context given as argument.  */\n  ctx->A = A;\n  ctx->B = B;\n  ctx->C = C;\n  ctx->D = D;\n}\n#elif defined(HAVE_OPENSSL_EVP)\n\nstruct ne_md5_ctx *ne_md5_create_ctx(void)\n{\n    struct ne_md5_ctx *ret;\n    EVP_MD_CTX *ctx;\n\n    ctx = EVP_MD_CTX_new();\n    if (!ctx) return NULL;\n\n    if (EVP_DigestInit(ctx, EVP_md5()) != 1) {\n        EVP_MD_CTX_free(ctx);\n        return NULL;\n    }\n\n    ret = ne_malloc(sizeof *ret);\n    ret->ctx = ctx;\n    return ret;\n}\n\nvoid ne_md5_process_block(const void *buffer, size_t len,\n                          struct ne_md5_ctx *ctx)\n{\n    EVP_DigestUpdate(ctx->ctx, buffer, len);\n}\n\nvoid ne_md5_process_bytes(const void *buffer, size_t len,\n                          struct ne_md5_ctx *ctx)\n{\n    EVP_DigestUpdate(ctx->ctx, buffer, len);\n}\n\nvoid *ne_md5_finish_ctx(struct ne_md5_ctx *ctx, void *resbuf)\n{\n    unsigned int len = MD5_DIGEST_LENGTH;\n    EVP_DigestFinal(ctx->ctx, resbuf, &len);\n    return resbuf;\n}\n\nstruct ne_md5_ctx *ne_md5_dup_ctx(struct ne_md5_ctx *ctx)\n{\n    struct ne_md5_ctx *ret;\n    EVP_MD_CTX *newctx;\n\n    newctx = EVP_MD_CTX_new();\n    if (!newctx) return NULL;\n\n    if (EVP_MD_CTX_copy_ex(newctx, ctx->ctx) != 1) {\n        EVP_MD_CTX_free(newctx);\n        return NULL;\n    }\n\n    ret = ne_malloc(sizeof *ret);\n    ret->ctx = newctx;\n    return ret;\n}\n\nvoid ne_md5_reset_ctx(struct ne_md5_ctx *ctx)\n{\n    EVP_MD_CTX_reset(ctx->ctx);\n}\n\nvoid ne_md5_destroy_ctx(struct ne_md5_ctx *ctx)\n{\n    EVP_MD_CTX_free(ctx->ctx);\n    ne_free(ctx);\n}\n\n#else /* OpenSSL < 3.1 */\nstruct ne_md5_ctx *ne_md5_create_ctx(void)\n{\n    struct ne_md5_ctx *ctx = ne_malloc(sizeof *ctx);\n    \n    if (MD5_Init(&ctx->ctx) != 1) {\n        ne_free(ctx);\n        return NULL;\n    }\n    \n    return ctx;\n}\n\nvoid ne_md5_process_block(const void *buffer, size_t len,\n                          struct ne_md5_ctx *ctx)\n{\n    MD5_Update(&ctx->ctx, buffer, len);\n}\n\nvoid ne_md5_process_bytes(const void *buffer, size_t len,\n                          struct ne_md5_ctx *ctx)\n{\n    MD5_Update(&ctx->ctx, buffer, len);\n}\n\nvoid *ne_md5_finish_ctx(struct ne_md5_ctx *ctx, void *resbuf)\n{\n    MD5_Final(resbuf, &ctx->ctx);\n    \n    return resbuf;\n}\n\nstruct ne_md5_ctx *ne_md5_dup_ctx(struct ne_md5_ctx *ctx)\n{\n    return memcpy(ne_malloc(sizeof *ctx), ctx, sizeof *ctx);\n}\n\nvoid ne_md5_reset_ctx(struct ne_md5_ctx *ctx)\n{\n    MD5_Init(&ctx->ctx);\n}\n    \nvoid ne_md5_destroy_ctx(struct ne_md5_ctx *ctx)\n{\n    ne_free(ctx);\n}\n#endif /* HAVE_OPENSSL */\n\n/* Put result from CTX in first 16 bytes following RESBUF.  The result\n   must be in little endian byte order.\n\n   IMPORTANT: On some systems it is required that RESBUF is correctly\n   aligned for a 32 bits value.  */\nvoid *\nmd5_read_ctx (const struct md5_ctx *ctx, void *resbuf)\n{\n#ifdef HAVE_OPENSSL_EVP\n  return NULL;\n#else\n\n#ifdef HAVE_OPENSSL\n#define SWAP_CTX(x) SWAP(ctx->ctx.x)\n#else\n#define SWAP_CTX(x) SWAP(ctx->x)\n#endif\n\n  ((md5_uint32 *) resbuf)[0] = SWAP_CTX (A);\n  ((md5_uint32 *) resbuf)[1] = SWAP_CTX (B);\n  ((md5_uint32 *) resbuf)[2] = SWAP_CTX (C);\n  ((md5_uint32 *) resbuf)[3] = SWAP_CTX (D);\n\n  return resbuf;\n#endif /* !HAVE_OPENSSL_EVP */\n}\n\n\n/* Compute MD5 message digest for bytes read from STREAM.  The\n   resulting message digest number will be written into the 16 bytes\n   beginning at RESBLOCK.  */\nint\nmd5_stream (FILE *stream, void *resblock)\n{\n  /* Important: BLOCKSIZE must be a multiple of 64.  */\n#define BLOCKSIZE 4096\n  struct ne_md5_ctx *ctx;\n  char buffer[BLOCKSIZE + 72];\n  size_t sum;\n\n  /* Initialize the computation context.  */\n  ctx = ne_md5_create_ctx ();\n\n  /* Iterate over full file contents.  */\n  while (1)\n    {\n      /* We read the file in blocks of BLOCKSIZE bytes.  One call of the\n\t computation function processes the whole buffer so that with the\n\t next round of the loop another block can be read.  */\n      size_t n;\n      sum = 0;\n\n      /* Read block.  Take care for partial reads.  */\n      do\n\t{\n\t  n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream);\n\n\t  sum += n;\n\t}\n      while (sum < BLOCKSIZE && n != 0);\n      if (n == 0 && ferror (stream))\n        return 1;\n\n      /* If end of file is reached, end the loop.  */\n      if (n == 0)\n\tbreak;\n\n      /* Process buffer with BLOCKSIZE bytes.  Note that\n\t\t\tBLOCKSIZE % 64 == 0\n       */\n      md5_process_block (buffer, BLOCKSIZE, ctx);\n    }\n\n  /* Add the last bytes if necessary.  */\n  if (sum > 0)\n    md5_process_bytes (buffer, sum, ctx);\n\n  /* Construct result in desired memory.  */\n  md5_finish_ctx (ctx, resblock);\n  ne_md5_destroy_ctx (ctx);\n  \n  return 0;\n}\n\n/* Writes the ASCII representation of the MD5 digest into the\n * given buffer, which must be at least 33 characters long. */\nvoid ne_md5_to_ascii(const unsigned char md5_buf[16], char *buffer) \n{\n    int count;\n    for (count = 0; count<16; count++) {\n\tbuffer[count*2] = NE_HEX2ASC(md5_buf[count] >> 4);\n\tbuffer[count*2+1] = NE_HEX2ASC(md5_buf[count] & 0x0f);\n    }\n    buffer[32] = '\\0';\n}\n\n/* Reads the ASCII representation of an MD5 digest. The buffer must\n * be at least 32 characters long. */\nvoid ne_ascii_to_md5(const char *buffer, unsigned char md5_buf[16]) \n{\n    int count;\n    for (count = 0; count<16; count++) {\n\tmd5_buf[count] = ((NE_ASC2HEX(buffer[count*2])) << 4) |\n\t    NE_ASC2HEX(buffer[count*2+1]);\n    }\n}\n\nchar *ne_md5_finish_ascii(struct ne_md5_ctx *ctx, char buffer[33])\n{\n    md5_uint32 result[4];\n\n    ne_md5_finish_ctx(ctx, (void *)result);\n    ne_md5_to_ascii((void *)result, buffer);\n\n    return buffer;\n}\n\n"
  },
  {
    "path": "src/ne_md5.h",
    "content": "/* Declaration of functions and data types used for MD5 sum computing\n   library functions.\n   Copyright (C) 2021, Joe Orton <joe@manyfish.co.uk>\n   Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.\n   This file is part of the GNU C Library.\n\n   The GNU C Library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public License as\n   published by the Free Software Foundation; either version 2 of the\n   License, or (at your option) any later version.\n\n   The GNU C Library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with the GNU C Library; see the file COPYING.LIB.  If not,\n   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,\n   Boston, MA 02111-1307, USA.  */\n\n#ifndef NE_MD5_H\n#define NE_MD5_H 1\n\n#include <stdio.h>\n\n#include \"ne_defs.h\"\n\nNE_BEGIN_DECLS\n\n/*\n * The following three functions are build up the low level used in\n * the functions `md5_stream' and `md5_buffer'.\n */\nstruct ne_md5_ctx;\n\n/* Create structure containing state of computation.  Can return NULL\n * if the MD5 algorithm is prohibited (such as FIPS-enabled\n * systems). */\nextern struct ne_md5_ctx *ne_md5_create_ctx(void);\n\n/* Starting with the result of former calls of this function (or the\n   initialization function update the context for the next LEN bytes\n   starting at BUFFER.\n   It is necessary that LEN is a multiple of 64!!! */\nextern void ne_md5_process_block(const void *buffer, size_t len,\n                                 struct ne_md5_ctx *ctx);\n\n/* Starting with the result of former calls of this function (or the\n   initialization function update the context for the next LEN bytes\n   starting at BUFFER.\n   It is NOT required that LEN is a multiple of 64.  */\nextern void ne_md5_process_bytes(const void *buffer, size_t len,\n                                 struct ne_md5_ctx *ctx);\n\n/* Process the remaining bytes in the buffer and put result from CTX\n   in first 16 bytes following RESBUF.  The result is always in little\n   endian byte order, so that a byte-wise output yields to the wanted\n   ASCII representation of the message digest.\n\n   IMPORTANT: On some systems it is required that RESBUF is correctly\n   aligned for a 32 bits value.  */\nextern void *ne_md5_finish_ctx(struct ne_md5_ctx *ctx, void *resbuf);\n\n\n/* Put result from CTX in first 16 bytes following RESBUF.  The result is\n   always in little endian byte order, so that a byte-wise output yields\n   to the wanted ASCII representation of the message digest.\n\n   IMPORTANT: On some systems it is required that RESBUF is correctly\n   aligned for a 32 bits value.\n\n   This function may return NULL if it is not possible to serialise\n   the intermediate state.  */\nextern void *ne_md5_read_ctx(const struct ne_md5_ctx *ctx, void *resbuf);\n\n/* Take a copy of the state structure. */\nextern struct ne_md5_ctx *ne_md5_dup_ctx(struct ne_md5_ctx *ctx);\n\n/* Re-initialize the context structure. */\nextern void ne_md5_reset_ctx(struct ne_md5_ctx *ctx);\n\n/* Destroy the context structure. */\nextern void ne_md5_destroy_ctx(struct ne_md5_ctx *ctx);\n\n/* Compute MD5 message digest for bytes read from STREAM.  The\n   resulting message digest number will be written into the 16 bytes\n   beginning at RESBLOCK.  */\nextern int ne_md5_stream(FILE *stream, void *resblock);\n\n/* Process the remaining bytes in the buffer and put ASCII\n   representation of the resulting message digest from CTX in the\n   first 33 bytes of BUFFER, including a trailing NUL terminator\n   byte.  Returns pointer to buffer. */\nchar *ne_md5_finish_ascii(struct ne_md5_ctx *ctx, char buffer[33]);\n\n/* MD5 ascii->binary conversion */\nvoid ne_md5_to_ascii(const unsigned char md5_buf[16], char *buffer);\nvoid ne_ascii_to_md5(const char *buffer, unsigned char md5_buf[16]);\n\nNE_END_DECLS\n\n#endif /* NE_MD5_H */\n"
  },
  {
    "path": "src/ne_oldacl.c",
    "content": "/*\n   Access control\n   Copyright (C) 2001-2021, Joe Orton <joe@manyfish.co.uk>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n\n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n\n/* Contributed by Arun Garg <arung@pspl.co.in> */\n\n#include \"config.h\"\n\n#include <sys/types.h>\n\n#ifdef HAVE_STRING_H\n#include <string.h>\n#endif\n#ifdef HAVE_UNISTD_H\n#include <unistd.h>\n#endif\n#ifdef HAVE_STDLIB_H\n#include <stdlib.h>\n#endif\n\n#include \"ne_request.h\"\n#include \"ne_locks.h\"\n#include \"ne_alloc.h\"\n#include \"ne_string.h\"\n#include \"ne_acl.h\"\n#include \"ne_uri.h\"\n#include \"ne_xml.h\" /* for NE_XML_MEDIA_TYPE */\n\n#define EOL \"\\r\\n\"\n\nstatic ne_buffer *acl_body(const ne_acl_entry *right, int count)\n{\n    ne_buffer *body = ne_buffer_create();\n    int m;\n\n    ne_buffer_zappend(body,\n\t\t      \"<?xml version=\\\"1.0\\\" encoding=\\\"utf-8\\\"?>\" EOL\n\t\t      \"<acl xmlns='DAV:'>\" EOL);\n\n    for (m = 0; m < count; m++) {\n\tconst char *type;\n\n\ttype = (right[m].type == ne_acl_grant ? \"grant\" : \"deny\");\n\n\tne_buffer_concat(body, \"<ace>\" EOL \"<principal>\", NULL);\n\n\tswitch (right[m].apply) {\n\tcase ne_acl_all:\n\t    ne_buffer_zappend(body, \"<all/>\" EOL);\n\t    break;\n\tcase ne_acl_property:\n\t    ne_buffer_concat(body, \"<property><\", right[m].principal,\n\t\t\t     \"/></property>\" EOL, NULL);\n\t    break;\n\tcase ne_acl_href:\n\t    ne_buffer_concat(body, \"<href>\", right[m].principal,\n\t\t\t     \"</href>\" EOL, NULL);\n\t    break;\n\t}\n\n\tne_buffer_concat(body, \"</principal>\" EOL \"<\", type, \">\" EOL, NULL);\n\t\n\tif (right[m].read == 0)\n\t    ne_buffer_concat(body,\n\t\t\t     \"<privilege>\" \"<read/>\" \"</privilege>\" EOL,\n\t\t\t     NULL);\n\tif (right[m].read_acl == 0)\n\t    ne_buffer_concat(body,\n\t\t\t     \"<privilege>\" \"<read-acl/>\" \"</privilege>\" EOL,\n\t\t\t     NULL);\n\tif (right[m].write == 0)\n\t    ne_buffer_concat(body,\n\t\t\t     \"<privilege>\" \"<write/>\" \"</privilege>\" EOL,\n\t\t\t     NULL);\n\tif (right[m].write_acl == 0)\n\t    ne_buffer_concat(body,\n\t\t\t     \"<privilege>\" \"<write-acl/>\" \"</privilege>\" EOL,\n\t\t\t     NULL);\n\tif (right[m].read_cuprivset == 0)\n\t    ne_buffer_concat(body,\n\t\t\t     \"<privilege>\"\n\t\t\t     \"<read-current-user-privilege-set/>\"\n\t\t\t     \"</privilege>\" EOL, NULL);\n\tne_buffer_concat(body, \"</\", type, \">\" EOL, NULL);\n\tne_buffer_zappend(body, \"</ace>\" EOL);\n    }\n    ne_buffer_zappend(body, \"</acl>\" EOL);\n\n    return body;\n}\n\nint ne_acl_set(ne_session *sess, const char *uri,\n\t       const ne_acl_entry *entries, int numentries)\n{\n    int ret;\n    ne_request *req = ne_request_create(sess, \"ACL\", uri);\n    ne_buffer *body = acl_body(entries, numentries);\n\n#ifdef NE_HAVE_DAV\n    ne_lock_using_resource(req, uri, 0);\n#endif\n\n    ne_set_request_body_buffer(req, body->data, ne_buffer_size(body));\n    ne_add_request_header(req, \"Content-Type\", NE_XML_MEDIA_TYPE);\n    ret = ne_request_dispatch(req);\n\n    ne_buffer_destroy(body);\n\n    if (ret == NE_OK && ne_get_status(req)->code == 207) {\n\tret = NE_ERROR;\n    }\n\n    ne_request_destroy(req);\n    return ret;\n}\n"
  },
  {
    "path": "src/ne_openssl.c",
    "content": "/* \n   neon SSL/TLS support using OpenSSL\n   Copyright (C) 2002-2025, Joe Orton <joe@manyfish.co.uk>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n   \n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n\n#include \"config.h\"\n\n#include <sys/types.h>\n\n#ifdef HAVE_STRING_H\n#include <string.h>\n#endif\n\n#include <stdio.h>\n\n#include <openssl/ssl.h>\n#include <openssl/err.h>\n#include <openssl/pkcs12.h>\n#include <openssl/x509v3.h>\n#include <openssl/rand.h>\n#include <openssl/opensslv.h>\n#include <openssl/evp.h>\n\n#if OPENSSL_VERSION_NUMBER >= 0x10100000L\n#define HAVE_OPENSSL110\n#endif\n\n#if defined(NE_HAVE_TS_SSL) && !defined(HAVE_OPENSSL110)\n/* From OpenSSL 1.1.0 locking callbacks are no longer needed. */\n#define WITH_OPENSSL_LOCKING (1)\n#include <stdlib.h> /* for abort() */\n#ifndef _WIN32\n#include <pthread.h>\n#endif\n#endif\n\n#include \"ne_ssl.h\"\n#include \"ne_string.h\"\n#include \"ne_internal.h\"\n#include \"ne_utils.h\"\n#include \"ne_privssl.h\"\n\n/* OpenSSL 0.9.6 compatibility */\n#if OPENSSL_VERSION_NUMBER < 0x0090700fL\n#define PKCS12_unpack_authsafes M_PKCS12_unpack_authsafes\n#define PKCS12_unpack_p7data M_PKCS12_unpack_p7data\n/* cast away lack of const-ness */\n#define OBJ_cmp(a,b) OBJ_cmp((ASN1_OBJECT *)(a), (ASN1_OBJECT *)(b))\n#endif\n\n/* Second argument for d2i_X509() changed type in 0.9.8. */\n#if OPENSSL_VERSION_NUMBER < 0x0090800fL\ntypedef unsigned char ne_d2i_uchar;\n#else\ntypedef const unsigned char ne_d2i_uchar;\n#endif\n\n/* Convert a ASCII decimal pair into an integer. */\n#define FROM_DEC(p_) (10*((p_)[0]-'0') + (p_)[1]-'0')\n\n#ifndef HAVE_OPENSSL110\n#define X509_get0_notBefore X509_get_notBefore\n#define X509_get0_notAfter X509_get_notAfter\n#define X509_up_ref(x) x->references++\n#define EVP_PKEY_up_ref(x) x->references++\n#define EVP_MD_CTX_new() ne_calloc(sizeof(EVP_MD_CTX))\n#define EVP_MD_CTX_free(ctx) ne_free(ctx)\n#define EVP_MD_CTX_reset EVP_MD_CTX_cleanup\n#define EVP_PKEY_get0_RSA(evp) (evp->pkey.rsa)\n#define ASN1_STRING_get0_data(as_) ((as_)->data)\n#define ASN1_STRING_length(as_) ((as_)->length)\n#define ASN1_STRING_type(as_) ((as_)->type)\n#endif\n\n#if OPENSSL_VERSION_NUMBER >= 0x10101000\n/* OpenSSL 1.1.1 has STORE. */\n#define HAVE_OPENSSL111\n#include <openssl/store.h>\n#include <openssl/ui.h>\n#else\n/* Backwards compatibility for <1.1.1. */\n#define TLS_client_method SSLv23_client_method\n#define TLS_server_method SSLv23_server_method\n#endif\n\nstruct ne_ssl_dname_s {\n    const X509_NAME *dn;\n};\n\nstruct ne_ssl_certificate_s {\n    ne_ssl_dname subj_dn, issuer_dn;\n    X509 *subject;\n    ne_ssl_certificate *issuer;\n    char *identity;\n};\n\nstruct ne_ssl_client_cert_s {\n    ne_ssl_certificate cert;\n    /* .decrypt is non-NULL if the clicert is in the encrypted state,\n     * and NULL in the decrypted state. */\n    int (*decrypt)(ne_ssl_client_cert *cc, const char *password);\n    PKCS12 *p12;\n    char *uri;\n    EVP_PKEY *pkey;\n    char *friendly_name;\n};\n\nstatic void free_cert(ne_ssl_certificate *cert);\n\n#define NE_SSL_UNHANDLED (0x20) /* failure bit for unhandled case. */\n\n/* Append an ASN.1 DirectoryString STR to buffer BUF as UTF-8.\n * Returns zero on success or non-zero on error. */\nstatic int append_dirstring(ne_buffer *buf, const ASN1_STRING *str)\n{\n    unsigned char *tmp = (unsigned char *)\"\"; /* initialize to workaround 0.9.6 bug */\n    const unsigned char *data = ASN1_STRING_get0_data(str);\n    int len = ASN1_STRING_length(str);\n    int type = ASN1_STRING_type(str);\n\n    switch (type) {\n    case V_ASN1_IA5STRING: /* definitely ASCII */\n    case V_ASN1_VISIBLESTRING: /* probably ASCII */\n    case V_ASN1_PRINTABLESTRING: /* subset of ASCII */\n        ne_buffer_qappend(buf, data, len);\n        break;\n    case V_ASN1_UTF8STRING:\n        /* Fail for embedded NUL bytes. */\n        if (strlen((const char *)data) != (size_t)len) {\n            return -1;\n        }\n        ne_buffer_append(buf, (char *)data, len);\n        break;\n    case V_ASN1_UNIVERSALSTRING:\n    case V_ASN1_T61STRING: /* let OpenSSL convert it as ISO-8859-1 */\n    case V_ASN1_BMPSTRING: \n        len = ASN1_STRING_to_UTF8(&tmp, str);\n        if (len > 0) {\n            /* Fail if there were embedded NUL bytes. */\n            if (strlen((char *)tmp) != (size_t)len) {\n                OPENSSL_free(tmp);\n                return -1;\n            } \n            else {\n                ne_buffer_append(buf, (char *)tmp, len);\n                OPENSSL_free(tmp);\n            }\n            break;\n        } else {\n            ERR_clear_error();\n            return -1;\n        }\n        break;\n    default:\n        NE_DEBUG(NE_DBG_SSL, \"Could not convert DirectoryString type %d\\n\",\n                 type);\n        return -1;\n    }\n    return 0;\n}\n\n/* Returns a malloc-allocated version of IA5 string AS, escaped for\n * safety. */\nstatic char *dup_ia5string(const ASN1_IA5STRING *as)\n{\n    const unsigned char *data = ASN1_STRING_get0_data(as);\n    int length = ASN1_STRING_length(as);\n\n    return ne_strnqdup(data, length);\n}\n\nchar *ne_ssl_readable_dname(const ne_ssl_dname *name)\n{\n    int n, flag = 0;\n    ne_buffer *dump = ne_buffer_create();\n    const ASN1_OBJECT * const cname = OBJ_nid2obj(NID_commonName),\n\t* const email = OBJ_nid2obj(NID_pkcs9_emailAddress);\n\n    for (n = X509_NAME_entry_count(name->dn); n > 0; n--) {\n\tconst X509_NAME_ENTRY *ent = X509_NAME_get_entry(name->dn, n-1);\n\tconst ASN1_OBJECT *obj = X509_NAME_ENTRY_get_object(ent);\n\t\n        /* Skip commonName or emailAddress except if there is no other\n         * attribute in dname. */\n\tif ((OBJ_cmp(obj, cname) && OBJ_cmp(obj, email)) ||\n            (!flag && n == 1)) {\n \t    if (flag++)\n\t\tne_buffer_append(dump, \", \", 2);\n\n            if (append_dirstring(dump, X509_NAME_ENTRY_get_data(ent)))\n                ne_buffer_czappend(dump, \"???\");\n\t}\n    }\n\n    return ne_buffer_finish(dump);\n}\n\nint ne_ssl_dname_cmp(const ne_ssl_dname *dn1, const ne_ssl_dname *dn2)\n{\n    return X509_NAME_cmp(dn1->dn, dn2->dn);\n}\n\nvoid ne_ssl_clicert_free(ne_ssl_client_cert *cc)\n{\n    if (cc->p12) PKCS12_free(cc->p12);\n    if (cc->uri) ne_free(cc->uri);\n    if (cc->pkey) EVP_PKEY_free(cc->pkey);\n    if (cc->friendly_name) ne_free(cc->friendly_name);\n    free_cert(&cc->cert);\n    ne_free(cc);\n}\n\n/* Convert an ASN1 time to time_t. */\nstatic time_t asn1time_to_timet(const ASN1_TIME *atm)\n{\n    struct tm tm = {0};\n\n#ifdef HAVE_ASN1_TIME_TO_TM\n    if (ASN1_TIME_to_tm(atm, &tm) != 1)\n        return (time_t)-1;\n#else\n    if (atm->length < 10)\n        return (time_t )-1;\n\n    tm.tm_year = FROM_DEC(atm->data);\n\n    /* Deal with Year 2000 */\n    if (tm.tm_year < 70)\n        tm.tm_year += 100;\n\n    tm.tm_mon = FROM_DEC(atm->data + 2) - 1;\n    tm.tm_mday = FROM_DEC(atm->data + 4);\n    tm.tm_hour = FROM_DEC(atm->data + 6);\n    tm.tm_min = FROM_DEC(atm->data + 8);\n    if (atm->length > 12)\n        tm.tm_sec = FROM_DEC(atm->data + 10);\n#endif\n\n#ifdef HAVE_TIMEGM\n    /* BSD/GNU; convert directly to GMT */\n    return timegm(&tm);\n#elif defined(HAVE_TIMEZONE) && !defined(HAVE_ASN1_TIME_TO_TM)\n    /* ASN1_TIME_to_tm already converts to GMT, otherwise\n     * use the timezone global offset to do so. */\n    return mktime(&tm) - timezone;\n#else\n    return mktime(&tm);\n#endif\n}\n\nvoid ne_ssl_cert_validity_time(const ne_ssl_certificate *cert,\n                               time_t *from, time_t *until)\n{\n    if (from) {\n        *from = asn1time_to_timet(X509_get0_notBefore(cert->subject));\n    }\n    if (until) {\n        *until = asn1time_to_timet(X509_get0_notAfter(cert->subject));\n    }\n}\n\n/* Check certificate identity per RFC 2818 and RFC 3280. */\nstatic int check_identity(const ne_ssl_certificate *server_cert,\n                          const char *hostname, const ne_inet_addr *address,\n                          char **identity)\n{\n    STACK_OF(GENERAL_NAME) *names;\n    int match = 0, found = 0;\n    X509 *cert = server_cert->subject;\n\n    if (!hostname) hostname = \"\";\n\n    names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);\n    if (names) {\n\tint n;\n\n        /* subjectAltName contains a sequence of GeneralNames */\n\tfor (n = 0; n < sk_GENERAL_NAME_num(names) && !match; n++) {\n\t    GENERAL_NAME *nm = sk_GENERAL_NAME_value(names, n);\n\t    \n            /* handle dNSName and iPAddress name extensions only. */\n\t    if (nm->type == GEN_DNS) {\n\t\tchar *name = dup_ia5string(nm->d.ia5);\n                if (identity && !found) *identity = ne_strdup(name);\n\n                /* Only match if the server was not identified by a\n                 * literal IP address; avoiding wildcard matches. */\n                if (!address)\n                    match = ne__ssl_match_hostname(name, strlen(name), hostname);\n\t\tne_free(name);\n\t\tfound = 1;\n            } \n            else if (nm->type == GEN_IPADD && address) {\n                /* compare IP address with server literal IP address. */\n                const unsigned char *data = ASN1_STRING_get0_data(nm->d.ip);\n                int len = ASN1_STRING_length(nm->d.ip);\n                ne_inet_addr *ia;\n\n                if (len == 4)\n                    ia = ne_iaddr_make(ne_iaddr_ipv4, data);\n                else if (len == 16)\n                    ia = ne_iaddr_make(ne_iaddr_ipv6, data);\n                else\n                    ia = NULL;\n                /* ne_iaddr_make returns NULL if address type is unsupported */\n                if (ia != NULL) { /* address type was supported. */\n                    match = ne_iaddr_cmp(ia, address) == 0;\n                    found = 1;\n                    ne_iaddr_free(ia);\n                }\n                else {\n                    NE_DEBUG(NE_DBG_SSL, \"ssl: iPAddress name with unsupported \"\n                             \"address type (length %d), skipped.\\n\", len);\n                }\n            }\n        }\n        /* free the whole stack. */\n        sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free);\n    }\n    \n    /* Check against the commonName if no DNS alt. names were found,\n     * as per RFC3280. */\n    if (!found) {\n\tconst X509_NAME *subj = X509_get_subject_name(cert);\n\tconst X509_NAME_ENTRY *entry;\n\tne_buffer *cname = ne_buffer_ncreate(30);\n\tint idx = -1, lastidx;\n\n\t/* find the most specific commonName attribute. */\n\tdo {\n\t    lastidx = idx;\n\t    idx = X509_NAME_get_index_by_NID(subj, NID_commonName, lastidx);\n\t} while (idx >= 0);\n\t\n\tif (lastidx < 0) {\n            /* no commonName attributes at all. */\n            ne_buffer_destroy(cname);\n\t    return -1;\n        }\n\n\t/* extract the string from the entry */\n        entry = X509_NAME_get_entry(subj, lastidx);\n        if (append_dirstring(cname, X509_NAME_ENTRY_get_data(entry))) {\n            ne_buffer_destroy(cname);\n            return -1;\n        }\n        if (identity) *identity = ne_strdup(cname->data);\n        if (!address)\n            match = ne__ssl_match_hostname(cname->data, cname->used-1, hostname);\n        ne_buffer_destroy(cname);\n    }\n\n    NE_DEBUG(NE_DBG_SSL, \"ssl: Identity match for '%s': %s\\n\",\n             hostname && *hostname ? hostname : \"(no host)\",\n             match ? \"good\" : \"bad\");\n    return match ? 0 : 1;\n}\n\n/* Populate an ne_ssl_certificate structure from an X509 object. */\nstatic ne_ssl_certificate *populate_cert(ne_ssl_certificate *cert, X509 *x5)\n{\n    cert->subj_dn.dn = X509_get_subject_name(x5);\n    cert->issuer_dn.dn = X509_get_issuer_name(x5);\n    cert->issuer = NULL;\n    cert->subject = x5;\n    /* Retrieve the cert identity; pass a dummy hostname to match. */\n    cert->identity = NULL;\n    check_identity(cert, NULL, NULL, &cert->identity);\n    return cert;\n}\n\n/* OpenSSL cert verification callback.  This is invoked for *each*\n * error which is encountered whilst verifying the cert chain; multiple\n * invocations for any particular cert in the chain are possible. */\nstatic int verify_callback(int ok, X509_STORE_CTX *ctx)\n{\n    /* OpenSSL, living in its own little happy world of global state,\n     * where userdata was just a twinkle in the eye of an API designer\n     * yet to be born.  Or... \"Seriously, wtf?\"  */\n    SSL *ssl = X509_STORE_CTX_get_ex_data(ctx, \n                                          SSL_get_ex_data_X509_STORE_CTX_idx());\n    ne_ssl_socket *sslsock = SSL_get_app_data(ssl);\n    int depth = X509_STORE_CTX_get_error_depth(ctx);\n    int err = X509_STORE_CTX_get_error(ctx);\n    int failures = 0;\n\n    /* If there's no error, nothing to do here. */\n    if (ok) return ok;\n\n    NE_DEBUG(NE_DBG_SSL, \"ssl: Verify callback @ %d => %d\\n\", depth, err);\n\n    /* Map the error code onto any of the exported cert validation\n     * errors, if possible. */\n    switch (err) {\n    case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:\n    case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:\n    case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:\n    case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:\n    case X509_V_ERR_CERT_UNTRUSTED:\n    case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:\n        failures |= NE_SSL_UNTRUSTED;\n        break;\n    case X509_V_ERR_CERT_NOT_YET_VALID:\n        failures |= depth > 0 ? NE_SSL_BADCHAIN : NE_SSL_NOTYETVALID;\n        break;\n    case X509_V_ERR_CERT_HAS_EXPIRED:\n        failures |= depth > 0 ? NE_SSL_BADCHAIN : NE_SSL_EXPIRED;\n        break;\n    case X509_V_OK:\n        break;\n    default:\n        /* Clear the failures bitmask so check_certificate knows this\n         * is a bailout. */\n        sslsock->failures |= NE_SSL_UNHANDLED;\n        NE_DEBUG(NE_DBG_SSL, \"ssl: Unhandled verification error %d -> %s\\n\", \n                 err, X509_verify_cert_error_string(err));\n        return 0;\n    }\n\n    sslsock->failures |= failures;\n\n    NE_DEBUG(NE_DBG_SSL, \"ssl: Verify failures |= %d => %d\\n\", failures,\n             sslsock->failures);\n    \n    return 1;\n}\n\n/* Return a linked list of certificate objects from an OpenSSL chain. */\nne_ssl_certificate *ne__ssl_make_chain(STACK_OF(X509) *chain)\n{\n    int n, count = sk_X509_num(chain);\n    ne_ssl_certificate *top = NULL, *current = NULL;\n    \n    NE_DEBUG(NE_DBG_SSL, \"Chain depth: %d\\n\", count);\n\n    for (n = 0; n < count; n++) {\n        ne_ssl_certificate *cert = ne_malloc(sizeof *cert);\n        populate_cert(cert, X509_dup(sk_X509_value(chain, n)));\n#ifdef NE_DEBUGGING\n        if (ne_debug_mask & NE_DBG_SSL) {\n            fprintf(ne_debug_stream, \"Cert #%d:\\n\", n);\n            X509_print_fp(ne_debug_stream, cert->subject);\n        }\n#endif\n        if (top == NULL) {\n            current = top = cert;\n        } else {\n            current->issuer = cert;\n            current = cert;\n        }\n    }\n\n    return top;\n}\n\n/* Verifies an SSL server certificate. */\nint ne_ssl_check_certificate(ne_ssl_context *ctx, ne_socket *sock,\n                             const char *hostname, const ne_inet_addr *address,\n                             const ne_ssl_certificate *cert,\n                             unsigned int flags, int *failures_out)\n{\n    ne_ssl_socket *sslsock = ne__sock_sslsock(sock);\n    int ret, failures = sslsock->failures;\n\n    /* If the verification callback hit a case which can't be mapped\n     * to one of the exported error bits, it's treated as a hard\n     * failure rather than invoking the callback, which can't present\n     * a useful error to the user.  \"Um, something is wrong.  OK?\" */\n    if (failures & NE_SSL_UNHANDLED) {\n        long result = SSL_get_verify_result(sslsock->ssl);\n        ne_sock_set_error(sock, _(\"Certificate verification error: %s\"),\n                          X509_verify_cert_error_string(result));\n        return NE_SOCK_ERROR;\n    }\n\n    /* Check certificate was issued to this server; pass URI of\n     * server. */\n    ret = check_identity(cert, hostname, address, NULL);\n    if (ret < 0) {\n        ne_sock_set_error(sock, _(\"Server certificate was missing commonName \"\n                                  \"attribute in subject name\"));\n        return NE_SOCK_ERROR;\n    } else if (ret > 0) failures |= NE_SSL_IDMISMATCH;\n\n    if (failures) {\n        /* Pass up the failures for possible override. */\n        ne__sock_set_verify_err(sock, failures);\n        *failures_out = failures;\n        ret = NE_SOCK_ERROR;\n    }\n\n    return ret;\n}\n\nne_ssl_client_cert *ne_ssl_clicert_copy(const ne_ssl_client_cert *cc)\n{\n    ne_ssl_client_cert *newcc = ne_calloc(sizeof *newcc);\n    \n    newcc->pkey = cc->pkey;\n    if (cc->friendly_name)\n        newcc->friendly_name = ne_strdup(cc->friendly_name);\n    if (cc->uri)\n        newcc->uri = ne_strdup(cc->uri);\n\n    populate_cert(&newcc->cert, cc->cert.subject);\n\n    X509_up_ref(cc->cert.subject);\n    EVP_PKEY_up_ref(cc->pkey);\n    return newcc;\n}\n\n/* Callback invoked when the SSL server requests a client certificate.  */\nstatic int provide_client_cert(SSL *ssl, X509 **cert, EVP_PKEY **pkey)\n{\n    ne_ssl_socket *sslsock = SSL_get_app_data(ssl);\n    SSL_CTX *const sslctx = SSL_get_SSL_CTX(ssl);\n    ne_ssl_context *const ctx = SSL_CTX_get_app_data(sslctx);\n\n    if (!ctx->client_cert && ctx->provider) {\n\tne_ssl_dname **dnames = NULL, *dnarray = NULL;\n        int n, count = 0;\n\tSTACK_OF(X509_NAME) *ca_list = SSL_get_client_CA_list(ssl);\n\n        count = ca_list ? sk_X509_NAME_num(ca_list) : 0;\n\n        if (count > 0) {\n            dnames = ne_malloc(count * sizeof(ne_ssl_dname *));\n            dnarray = ne_malloc(count * sizeof(ne_ssl_dname));\n            \n            for (n = 0; n < count; n++) {\n                dnames[n] = &dnarray[n];\n                dnames[n]->dn = sk_X509_NAME_value(ca_list, n);\n            }\n        }\n\n\tNE_DEBUG(NE_DBG_SSL, \"Calling client certificate provider...\\n\");\n\tctx->provider(ctx->provider_ud,\n                      (const ne_ssl_dname *const *)dnames, count);\n        if (count) {\n            ne_free(dnarray);\n            ne_free(dnames);\n        }\n    }\n\n    if (ctx->client_cert) {\n        ne_ssl_client_cert *cc = ctx->client_cert;\n        NE_DEBUG(NE_DBG_SSL, \"ssl: Supplying client certificate.\\n\");\n        EVP_PKEY_up_ref(cc->pkey);\n        X509_up_ref(cc->cert.subject);\n        *cert = cc->cert.subject;\n        *pkey = cc->pkey;\n        return 1;\n    }\n    else {\n        sslsock->cc_requested = 1;\n        NE_DEBUG(NE_DBG_SSL, \"ssl: No client certificate supplied.\\n\");\n        return 0;\n    }\n}\n\nstatic int new_ssl_session(SSL *ssl, SSL_SESSION *sslsess)\n{\n    SSL_CTX *sslctx = SSL_get_SSL_CTX(ssl);\n    ne_ssl_context *sctx = SSL_CTX_get_app_data(sslctx);\n\n    if (sctx->sess)\n        SSL_SESSION_free(sctx->sess);\n\n    NE_DEBUG(NE_DBG_SSL, \"sslsess: New session callback: %s.\\n\",\n             SSL_SESSION_is_resumable(sslsess) ? \"resumable\" : \"not resumable\");\n\n    sctx->sess = SSL_SESSION_dup(sslsess);\n    return 1;\n}\n\nstatic void remove_ssl_session(SSL_CTX *sslctx, SSL_SESSION *sess)\n{\n    ne_ssl_context *ctx = SSL_CTX_get_app_data(sslctx);\n\n    NE_DEBUG(NE_DBG_SSL, \"sslsess: Remove session callback.\\n\");\n\n    if (ctx->sess && sess == ctx->sess) {\n        SSL_SESSION_free(ctx->sess);\n        ctx->sess = NULL;\n    }\n}\n\nne_ssl_context *ne_ssl_context_create(int mode)\n{\n    ne_ssl_context *ctx = ne_calloc(sizeof *ctx);\n\n    if (mode == NE_SSL_CTX_CLIENT) {\n        ctx->ctx = SSL_CTX_new(TLS_client_method());\n        ctx->sess = NULL;\n        /* set client cert callback. */\n        SSL_CTX_set_client_cert_cb(ctx->ctx, provide_client_cert);\n        /* enable workarounds for buggy SSL server implementations */\n        SSL_CTX_set_options(ctx->ctx, SSL_OP_ALL);\n        SSL_CTX_set_verify(ctx->ctx, SSL_VERIFY_PEER, verify_callback);\n#if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER >= 0x3040000fL || (!defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10101000L)\n        SSL_CTX_set_post_handshake_auth(ctx->ctx, 1);\n#endif\n        SSL_CTX_set_app_data(ctx->ctx, ctx);\n        SSL_CTX_sess_set_new_cb(ctx->ctx, new_ssl_session);\n        SSL_CTX_sess_set_remove_cb(ctx->ctx, remove_ssl_session);\n        SSL_CTX_set_session_cache_mode(ctx->ctx, SSL_SESS_CACHE_CLIENT|SSL_SESS_CACHE_NO_INTERNAL);\n    }\n    else /* mode == NE_SSL_CTX_SERVER */ {\n        char sidctx[128];\n        ctx->ctx = SSL_CTX_new(TLS_server_method());\n#ifdef SSL_OP_NO_TICKET\n        /* disable ticket support since it inhibits testing of session\n         * caching. */\n        SSL_CTX_set_options(ctx->ctx, SSL_OP_NO_TICKET);\n#endif\n        ne_snprintf(sidctx, sizeof sidctx, \"%s-%p\", PACKAGE_NAME, ctx);\n        SSL_CTX_set_session_id_context(ctx->ctx, (unsigned char *)sidctx,\n                                       strlen(sidctx));\n    }\n    return ctx;\n}\n\nvoid ne_ssl_context_set_flag(ne_ssl_context *ctx, int flag, int value)\n{\n}\n\nint ne_ssl_context_get_flag(ne_ssl_context *ctx, int flag)\n{\n    return 0;\n}\n\nint ne_ssl_context_keypair(ne_ssl_context *ctx, const char *cert,\n                           const char *key)\n{\n    int ret;\n\n    ret = SSL_CTX_use_PrivateKey_file(ctx->ctx, key, SSL_FILETYPE_PEM);\n    if (ret == 1) {\n        ret = SSL_CTX_use_certificate_chain_file(ctx->ctx, cert);\n    }\n\n    return ret == 1 ? 0 : -1;\n}\n\nint ne_ssl_context_set_verify(ne_ssl_context *ctx, \n                              int required,\n                              const char *ca_names,\n                              const char *verify_cas)\n{\n    if (required) {\n        SSL_CTX_set_verify(ctx->ctx, SSL_VERIFY_PEER | \n                           SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);\n    }\n    if (ca_names) {\n        SSL_CTX_set_client_CA_list(ctx->ctx, \n                                   SSL_load_client_CA_file(ca_names));\n    }\n    if (verify_cas) {\n        SSL_CTX_load_verify_locations(ctx->ctx, verify_cas, NULL);\n    }\n    return 0;\n}\n\n#ifdef HAVE_OPENSSL110\n/* Map neon version constants to native OpenSSL constants, returns -1\n * on versions not supported. */\nstatic int proto_to_native(enum ne_ssl_protocol proto)\n{\n    switch (proto) {\n    case NE_SSL_PROTO_UNSPEC: return 0;\n    case NE_SSL_PROTO_SSL_3: return SSL3_VERSION;\n    case NE_SSL_PROTO_TLS_1_0: return TLS1_VERSION;\n    case NE_SSL_PROTO_TLS_1_1: return TLS1_1_VERSION;\n#ifdef TLS1_2_VERSION\n    case NE_SSL_PROTO_TLS_1_2: return TLS1_2_VERSION;\n#endif\n#ifdef TLS1_3_VERSION\n    case NE_SSL_PROTO_TLS_1_3: return TLS1_3_VERSION;\n#endif\n    default:\n        return -1;\n    }\n}\n#endif\n\nint ne_ssl_context_set_versions(ne_ssl_context *ctx, enum ne_ssl_protocol min,\n                                enum ne_ssl_protocol max)\n{\n#ifdef HAVE_OPENSSL110\n    int omin = proto_to_native(min), omax = proto_to_native(max), ret;\n\n    if (omin < 0 || omax < 0) {\n        return NE_SOCK_ERROR;\n    }\n\n    if ((ret = SSL_CTX_set_min_proto_version(ctx->ctx, omin)) == 1)\n        ret = SSL_CTX_set_max_proto_version(ctx->ctx, omax);\n\n    ERR_clear_error();\n    \n    return ret == 1 ? 0 : NE_SOCK_ERROR;\n#else\n    return NE_SOCK_ERROR;\n#endif\n}\n\nvoid ne_ssl_context_destroy(ne_ssl_context *ctx)\n{\n    SSL_CTX_free(ctx->ctx);\n    if (ctx->sess)\n        SSL_SESSION_free(ctx->sess);\n    if (ctx->client_cert)\n        ne_ssl_clicert_free(ctx->client_cert);\n    ne_free(ctx);\n}\n\nconst ne_ssl_dname *ne_ssl_cert_issuer(const ne_ssl_certificate *cert)\n{\n    return &cert->issuer_dn;\n}\n\nconst ne_ssl_dname *ne_ssl_cert_subject(const ne_ssl_certificate *cert)\n{\n    return &cert->subj_dn;\n}\n\nconst ne_ssl_certificate *ne_ssl_cert_signedby(const ne_ssl_certificate *cert)\n{\n    return cert->issuer;\n}\n\nconst char *ne_ssl_cert_identity(const ne_ssl_certificate *cert)\n{\n    return cert->identity;\n}\n\nvoid ne_ssl_context_trustcert(ne_ssl_context *ctx, const ne_ssl_certificate *cert)\n{\n    X509_STORE *store = SSL_CTX_get_cert_store(ctx->ctx);\n    \n    X509_STORE_add_cert(store, cert->subject);\n}\n\nvoid ne_ssl_context_set_clicert(ne_ssl_context *ctx, const ne_ssl_client_cert *cc)\n{\n    if (ctx->client_cert) ne_ssl_clicert_free(ctx->client_cert);\n    ctx->client_cert = ne_ssl_clicert_copy(cc);\n}\n\nvoid ne_ssl_context_trustdefca(ne_ssl_context *ctx)\n{\n    X509_STORE *store = SSL_CTX_get_cert_store(ctx->ctx);\n    \n#ifdef NE_SSL_CA_BUNDLE\n    X509_STORE_load_locations(store, NE_SSL_CA_BUNDLE, NULL);\n#else\n    X509_STORE_set_default_paths(store);\n#endif\n}\n\n/* Find a friendly name in a PKCS12 structure the hard way, without\n * decrypting the parts which are encrypted.. */\nstatic char *find_friendly_name(PKCS12 *p12)\n{\n    STACK_OF(PKCS7) *safes = PKCS12_unpack_authsafes(p12);\n    int n, m;\n    char *name = NULL;\n\n    if (safes == NULL) return NULL;\n    \n    /* Iterate over the unpacked authsafes: */\n    for (n = 0; n < sk_PKCS7_num(safes) && !name; n++) {\n        PKCS7 *safe = sk_PKCS7_value(safes, n);\n        STACK_OF(PKCS12_SAFEBAG) *bags;\n    \n        /* Only looking for unencrypted authsafes. */\n        if (OBJ_obj2nid(safe->type) != NID_pkcs7_data) continue;\n\n        bags = PKCS12_unpack_p7data(safe);\n        if (!bags) continue;\n\n        /* Iterate through the bags, picking out a friendly name */\n        for (m = 0; m < sk_PKCS12_SAFEBAG_num(bags) && !name; m++) {\n            PKCS12_SAFEBAG *bag = sk_PKCS12_SAFEBAG_value(bags, m);\n            name = PKCS12_get_friendlyname(bag);\n        }\n    \n        sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free);\n    }\n\n    sk_PKCS7_pop_free(safes, PKCS7_free);\n    return name;\n}\n\nstatic int pkcs12_decrypt(ne_ssl_client_cert *cc, const char *password);\n\nstatic ne_ssl_client_cert *parse_client_cert(PKCS12 *p12)\n{\n    X509 *cert;\n    EVP_PKEY *pkey;\n    ne_ssl_client_cert *cc;\n\n    if (p12 == NULL) {\n        ERR_clear_error();\n        return NULL;\n    }\n\n    /* Try parsing with no password. */\n    if (PKCS12_parse(p12, NULL, &pkey, &cert, NULL) == 1) {\n        /* Success - no password needed for decryption. */\n        int len = 0;\n        const unsigned char *name;\n\n        if (!cert || !pkey) {\n            PKCS12_free(p12);\n            return NULL;\n        }\n\n        name = X509_alias_get0(cert, &len);\n        \n        cc = ne_calloc(sizeof *cc);\n        cc->pkey = pkey;\n        if (name && len > 0)\n            cc->friendly_name = ne_strndup((char *)name, len);\n        populate_cert(&cc->cert, cert);\n        PKCS12_free(p12);\n        return cc;\n    } else {\n        /* Failed to parse the file */\n        int err = ERR_get_error();\n        ERR_clear_error();\n        if (ERR_GET_LIB(err) == ERR_LIB_PKCS12 &&\n            ERR_GET_REASON(err) == PKCS12_R_MAC_VERIFY_FAILURE) {\n            /* Decryption error due to bad password. */\n            cc = ne_calloc(sizeof *cc);\n            cc->friendly_name = find_friendly_name(p12);\n            cc->p12 = p12;\n            cc->decrypt = pkcs12_decrypt;\n            return cc;\n        } else {\n            /* Some parse error, give up. */\n            PKCS12_free(p12);\n            return NULL;\n        }\n    }\n}\n\nne_ssl_client_cert *ne_ssl_clicert_import(const unsigned char *buffer, \n                                          size_t buflen)\n{\n    ne_d2i_uchar *p;\n    PKCS12 *p12;\n\n    p = buffer;\n    p12 = d2i_PKCS12(NULL, &p, buflen);\n    \n    return parse_client_cert(p12);\n}\n    \nne_ssl_client_cert *ne_ssl_clicert_read(const char *filename)\n{\n    PKCS12 *p12;\n    FILE *fp;\n\n    fp = fopen(filename, \"rb\");\n    if (fp == NULL)\n        return NULL;\n\n    p12 = d2i_PKCS12_fp(fp, NULL);\n\n    fclose(fp);\n\n    return parse_client_cert(p12);\n}\n\n#ifdef HAVE_OPENSSL111\n\nstatic int ui_reader(UI *ui, UI_STRING *uis)\n{\n    const char *password = UI_get0_user_data(ui);\n    enum UI_string_types uit = UI_get_string_type(uis);\n    int ret = 0;\n\n    if (uit != UIT_PROMPT) return -1;\n\n    if (UI_set_result(ui, uis, password) != 0) {\n        unsigned long err = ERR_get_error();\n        NE_DEBUG(NE_DBG_SSL, \"pk11: Result set failed: %s.\\n\",\n                 ERR_reason_error_string(err));\n    }\n    else {\n        NE_DEBUG(NE_DBG_SSL, \"pk11: Result set successfully.\\n\");\n        ret = 1;\n    }\n\n    return ret;\n}\n\n/* Iterate through an OSSL_STORE - possibly supplying decryption\n * password if non-NULL. */\nstatic int store_iterate(ne_ssl_client_cert *cc, const char *password)\n{\n    X509 *cert = NULL;\n    EVP_PKEY *pkey = NULL;\n    OSSL_STORE_CTX *store;\n    UI_METHOD *ui;\n\n    if (password) {\n        ui = UI_create_method(\"neon\");\n        UI_method_set_reader(ui, ui_reader);\n    }\n    else {\n        ui = NULL;\n    }\n\n    /* Clear any existing cert data to ensure each iteration fetches a\n     * matching cert/key pair. */\n    free_cert(&cc->cert);\n\n    NE_DEBUG(NE_DBG_SSL, \"ssl: Opening store for %s...\\n\", cc->uri);\n    store = OSSL_STORE_open(cc->uri, ui, (char *)password, NULL, NULL);\n    if (!store) {\n        NE_DEBUG(NE_DBG_SSL, \"ssl: Failed to open store.\\n\");\n        return ENODEV;\n    }\n\n    while (!OSSL_STORE_eof(store)) {\n        OSSL_STORE_INFO *info = OSSL_STORE_load(store);\n\n        if (!info) {\n            /* OSSL_STORE_load() returns NULL once reaching EOF, or on\n             * error - e.g. for an encrypted PKEY. Log but ignore any\n             * errors. */\n#ifdef NE_DEBUGGING\n            unsigned long err = ERR_get_error();\n            NE_DEBUG(NE_DBG_SSL, \"ssl: Store load failed (eof: %s): %s\\n\",\n                     OSSL_STORE_eof(store) ? \"yes\" : \"no\",\n                     err ? ERR_reason_error_string(err) : \"(no error)\");\n#endif\n            ERR_clear_error();\n            continue;\n        }\n\n        switch (OSSL_STORE_INFO_get_type(info)) {\n        case OSSL_STORE_INFO_CERT:\n            if (!cert) {\n                NE_DEBUG(NE_DBG_SSL, \"ssl: STORE got CERT.\\n\");\n                cert = OSSL_STORE_INFO_get1_CERT(info);\n            }\n            break;\n        case OSSL_STORE_INFO_PKEY:\n            if (!pkey) {\n                NE_DEBUG(NE_DBG_SSL, \"ssl: STORE got PKEY.\\n\");\n                pkey = OSSL_STORE_INFO_get1_PKEY(info);\n            }\n            break;\n        }\n\n        OSSL_STORE_INFO_free(info);\n    }\n\n    OSSL_STORE_close(store);\n    NE_DEBUG(NE_DBG_SSL, \"ssl: End of store.\\n\");\n    if (ui) UI_destroy_method(ui);\n\n    if (!cert) {\n        if (pkey) EVP_PKEY_free(pkey);\n        return ENOENT;\n    }\n\n    /* Fail early if both a cert&pkey are found but don't match. */\n    if (pkey && X509_check_private_key(cert, pkey) != 1) {\n        ERR_clear_error();\n        X509_free(cert);\n        EVP_PKEY_free(pkey);\n        NE_DEBUG(NE_DBG_SSL, \"ssl: Decrypted private key/cert are not matched.\");\n        return EINVAL;\n    }\n\n    /* Store/extract the X509 in the cc object. */\n    populate_cert(&cc->cert, cert);\n\n    if (pkey) {\n        /* Successfully extracted both a cert & pkey. */\n        cc->pkey = pkey;\n        cc->decrypt = NULL;\n        return 0;\n    }\n\n    /* If this was a _decrypt() call (password must be non-NULL),\n     * return an error if a privkey wasn't available. Otherwise (NULL\n     * password), this is the first iteration through the STORE for\n     * the clicert object, succeed and set up for future decryption */\n    if (password) {\n        return EAGAIN;\n    }\n    else {\n        cc->decrypt = store_iterate;\n        return 0;\n    }\n}\n\nne_ssl_client_cert *ne_ssl_clicert_fromuri(const char *uri,\n                                           unsigned int flags)\n{\n    ne_ssl_client_cert *cc = ne_calloc(sizeof *cc);\n    int errnum;\n\n    cc->uri = ne_strdup(uri);\n    if ((errnum = store_iterate(cc, NULL)) != 0) {\n        ne_free(cc->uri);\n        ne_free(cc);\n        errno = errnum;\n        return NULL;\n    }\n    return cc;\n}\n\n#endif\n\n#ifdef HAVE_PAKCHOIS\nstatic ne_ssl_client_cert *clicert_from_keypair(X509 *cert, EVP_PKEY *key)\n{\n    ne_ssl_client_cert *cc = ne_calloc(sizeof *cc);\n\n    cc->pkey = key;\n    populate_cert(&cc->cert, cert);\n\n    return cc;\n}\n\nne_ssl_client_cert *ne__ssl_clicert_exkey_import(const unsigned char *der,\n                                                 size_t der_len,\n                                                 const RSA_METHOD *method)\n{\n    ne_d2i_uchar *p;\n    X509 *x5;\n    EVP_PKEY *pubkey, *privkey;\n    RSA *rsa;\n\n    p = der;\n    x5 = d2i_X509(NULL, &p, der_len); /* p is incremented */\n    if (x5 == NULL) {\n        ERR_clear_error();\n        return NULL;\n    }\n\n    pubkey = X509_get_pubkey(x5);\n    if (EVP_PKEY_base_id(pubkey) != EVP_PKEY_RSA) {\n        X509_free(x5);\n        NE_DEBUG(NE_DBG_SSL, \"ssl: Only RSA private keys are supported via PKCS#11.\\n\");\n        return NULL;\n    }\n\n    /* Duplicate the public parameters of the RSA key. */\n    rsa = RSAPublicKey_dup(EVP_PKEY_get0_RSA(pubkey));\n    /* Done with the copied public key. */\n    EVP_PKEY_free(pubkey);\n    \n    /* Switch to using customer RSA_METHOD for RSA object. */\n    RSA_set_method(rsa, method);\n    /* Set up new EVP_PKEY. */\n    privkey = EVP_PKEY_new();\n    EVP_PKEY_assign_RSA(privkey, rsa);\n\n    return clicert_from_keypair(x5, privkey);\n}\n#endif\n\nint ne_ssl_clicert_encrypted(const ne_ssl_client_cert *cc)\n{\n    return cc->decrypt != NULL;\n}\n\nstatic int pkcs12_decrypt(ne_ssl_client_cert *cc, const char *password)\n{\n    X509 *cert;\n    EVP_PKEY *pkey;\n\n    if (PKCS12_parse(cc->p12, password, &pkey, &cert, NULL) != 1) {\n        ERR_clear_error();\n        return EACCES;\n    }\n    \n    if (X509_check_private_key(cert, pkey) != 1) {\n        ERR_clear_error();\n        X509_free(cert);\n        EVP_PKEY_free(pkey);\n        NE_DEBUG(NE_DBG_SSL, \"ssl: Decrypted private key/cert are not matched.\");\n        return EINVAL;\n    }\n\n    PKCS12_free(cc->p12);\n    populate_cert(&cc->cert, cert);\n    cc->pkey = pkey;\n    cc->decrypt = NULL;\n    cc->p12 = NULL;\n    return 0;\n}\n\nint ne_ssl_clicert_decrypt(ne_ssl_client_cert *cc, const char *password)\n{\n    int errnum = cc->decrypt ? cc->decrypt(cc, password) : EINVAL;\n    return errnum != 0;\n}\n\nconst ne_ssl_certificate *ne_ssl_clicert_owner(const ne_ssl_client_cert *cc)\n{\n    return &cc->cert;\n}\n\nconst char *ne_ssl_clicert_name(const ne_ssl_client_cert *cc)\n{\n    return cc->friendly_name ? cc->friendly_name : cc->uri;\n}\n\nne_ssl_certificate *ne_ssl_cert_read(const char *filename)\n{\n    FILE *fp = fopen(filename, \"r\");\n    X509 *cert;\n\n    if (fp == NULL)\n        return NULL;\n\n    cert = PEM_read_X509(fp, NULL, NULL, NULL);\n    fclose(fp);\n\n    if (cert == NULL) {\n        NE_DEBUG(NE_DBG_SSL, \"d2i_X509_fp failed: %s\\n\", \n                 ERR_reason_error_string(ERR_get_error()));\n        ERR_clear_error();\n        return NULL;\n    }\n\n    return populate_cert(ne_calloc(sizeof(struct ne_ssl_certificate_s)), cert);\n}\n\nint ne_ssl_cert_write(const ne_ssl_certificate *cert, const char *filename)\n{\n    FILE *fp = fopen(filename, \"w\");\n\n    if (fp == NULL) return -1;\n\n    if (PEM_write_X509(fp, cert->subject) != 1) {\n        ERR_clear_error();\n        fclose(fp);\n        return -1;\n    }\n    \n    if (fclose(fp) != 0)\n        return -1;\n\n    return 0;\n}\n\nstatic void free_cert(ne_ssl_certificate *cert)\n{\n    X509_free(cert->subject);\n    if (cert->issuer)\n        ne_ssl_cert_free(cert->issuer);\n    if (cert->identity)\n        ne_free(cert->identity);\n}\n\nvoid ne_ssl_cert_free(ne_ssl_certificate *cert)\n{\n    free_cert(cert);\n    ne_free(cert);\n}\n\nint ne_ssl_cert_cmp(const ne_ssl_certificate *c1, const ne_ssl_certificate *c2)\n{\n    return X509_cmp(c1->subject, c2->subject);\n}\n\n/* The certificate import/export format is the base64 encoding of the\n * raw DER; PEM without the newlines and wrapping. */\n\nne_ssl_certificate *ne_ssl_cert_import(const char *data)\n{\n    unsigned char *der;\n    ne_d2i_uchar *p;\n    size_t len;\n    X509 *x5;\n    \n    /* decode the base64 to get the raw DER representation */\n    len = ne_unbase64(data, &der);\n    if (len == 0) return NULL;\n\n    p = der;\n    x5 = d2i_X509(NULL, &p, len); /* p is incremented */\n    ne_free(der);\n    if (x5 == NULL) {\n        ERR_clear_error();\n        return NULL;\n    }\n\n    return populate_cert(ne_calloc(sizeof(struct ne_ssl_certificate_s)), x5);\n}\n\nchar *ne_ssl_cert_export(const ne_ssl_certificate *cert)\n{\n    int len;\n    unsigned char *der, *p;\n    char *ret;\n    \n    /* find the length of the DER encoding. */\n    len = i2d_X509(cert->subject, NULL);\n\n    p = der = ne_malloc(len);\n    i2d_X509(cert->subject, &p); /* p is incremented */\n\n    ret = ne_base64(der, len);\n    ne_free(der);\n    return ret;\n}\n\nstatic const EVP_MD *hash_to_md(unsigned int flags)\n{\n    switch (flags & NE_HASH_ALGMASK) {\n    case NE_HASH_MD5: return EVP_md5();\n    case NE_HASH_SHA1: return EVP_sha1();\n    case NE_HASH_SHA256: return EVP_sha256();\n#ifdef HAVE_OPENSSL11\n    case NE_HASH_SHA512: return EVP_sha512();\n#if !defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER >= 0x3080000fL\n    case NE_HASH_SHA512_256: return EVP_sha512_256();\n#endif\n#endif\n    default: break;\n    }\n    return NULL;\n}\n\n#if SHA_DIGEST_LENGTH != 20\n# error SHA digest length is not 20 bytes\n#endif\n\nchar *ne_ssl_cert_hdigest(const ne_ssl_certificate *cert, unsigned int flags)\n{\n    const EVP_MD *md = hash_to_md(flags);\n    unsigned char dig[EVP_MAX_MD_SIZE];\n    unsigned int len;\n\n    if (!md) return NULL;\n\n    if (!X509_digest(cert->subject, md, dig, &len)) {\n        ERR_clear_error();\n        return NULL;\n    }\n\n    return ne__strhash2hex(dig, len, flags);\n}\n\nint ne_ssl_cert_digest(const ne_ssl_certificate *cert, char *digest)\n{\n    unsigned char sha1[EVP_MAX_MD_SIZE];\n    unsigned int len, j;\n    char *p;\n\n    if (!X509_digest(cert->subject, EVP_sha1(), sha1, &len) || len != 20) {\n        ERR_clear_error();\n        return -1;\n    }\n    \n    for (j = 0, p = digest; j < 20; j++) {\n        *p++ = NE_HEX2ASC((sha1[j] >> 4) & 0x0f);\n        *p++ = NE_HEX2ASC(sha1[j] & 0x0f);\n        *p++ = ':';\n    }\n\n    p[-1] = '\\0';\n    return 0;\n}\n\nchar *ne_vstrhash(unsigned int flags, va_list ap)\n{\n    EVP_MD_CTX *ctx;\n    const EVP_MD *md = hash_to_md(flags);\n    unsigned char v[EVP_MAX_MD_SIZE];\n    unsigned int vlen;\n    const char *arg;\n\n    ctx = EVP_MD_CTX_new();\n    if (!ctx) return NULL;\n\n    if (EVP_DigestInit(ctx, md) != 1) {\n        EVP_MD_CTX_free(ctx);\n        return NULL;\n    }\n\n    while ((arg = va_arg(ap, const char *)) != NULL)\n        EVP_DigestUpdate(ctx, arg, strlen(arg));\n\n    EVP_DigestFinal_ex(ctx, v, &vlen);\n    EVP_MD_CTX_free(ctx);\n\n    return ne__strhash2hex(v, vlen, flags);\n}\n\nint ne_mknonce(unsigned char *nonce, size_t len, unsigned int flags)\n{\n    if (RAND_status() == 1 && RAND_bytes(nonce, len) == 1)\n        return 0;\n    else\n        return EAGAIN;\n}\n\n#ifdef WITH_OPENSSL_LOCKING\n/* Implementation of locking callbacks to make OpenSSL thread-safe.\n * If the OpenSSL API was better designed, this wouldn't be necessary.\n * In OpenSSL releases without CRYPTO_set_idptr_callback, it's not\n * possible to implement the locking in a POSIX-compliant way, since\n * it's necessary to cast from a pthread_t to an unsigned long at some\n * point.  */\n\n#ifndef _WIN32\nstatic pthread_mutex_t *locks;\n#else\nstatic HANDLE *locks;\n#endif\nstatic size_t num_locks;\n\n#ifndef HAVE_CRYPTO_SET_IDPTR_CALLBACK\n/* Named to be obvious when it shows up in a backtrace. */\nstatic unsigned long thread_id_neon(void)\n{\n#ifndef _WIN32\n    /* This will break if pthread_t is a structure; upgrading OpenSSL\n     * >= 0.9.9 (which does not require this callback) is the only\n     * solution.  */\n    return (unsigned long) pthread_self();\n#else\n    return (unsigned long) GetCurrentThreadId();\n#endif\n}\n#endif\n\n/* Another great API design win for OpenSSL: no return value!  So if\n * the lock/unlock fails, all that can be done is to abort. */\nstatic void thread_lock_neon(int mode, int n, const char *file, int line)\n{\n    if (mode & CRYPTO_LOCK) {\n#ifndef _WIN32\n        if (pthread_mutex_lock(&locks[n])) {\n#else\n        if (WaitForSingleObject(locks[n], INFINITE)) {\n#endif\n            abort();\n        }\n    }\n    else {\n#ifndef _WIN32\n        if (pthread_mutex_unlock(&locks[n])) {\n#else\n        if (!ReleaseMutex(locks[n])) {\n#endif\n            abort();\n        }\n    }\n}\n\n/* ID_CALLBACK_IS_{NEON,OTHER} evaluate as true if the currently\n * registered OpenSSL ID callback is the neon function (_NEON), or has\n * been overwritten by some other app (_OTHER). */\n#ifdef HAVE_CRYPTO_SET_IDPTR_CALLBACK\n#define ID_CALLBACK_IS_OTHER (0)\n#define ID_CALLBACK_IS_NEON (1)\n#else\n#define ID_CALLBACK_IS_OTHER (CRYPTO_get_id_callback() != NULL)\n#define ID_CALLBACK_IS_NEON (CRYPTO_get_id_callback() == thread_id_neon)\n#endif\n        \n#endif /* NE_HAVE_TS_SSL && OPENSSL_VERSION_NUMBER < 1.1.1 */\n\nint ne__ssl_init(void)\n{\n#if OPENSSL_VERSION_NUMBER < 0x10100000L\n    CRYPTO_malloc_init();\n    SSL_load_error_strings();\n    SSL_library_init();\n    OpenSSL_add_all_algorithms();\n\n#ifdef WITH_OPENSSL_LOCKING\n    /* If some other library has already come along and set up the\n     * thread-safety callbacks, then it must be presumed that the\n     * other library will have a longer lifetime in the process than\n     * neon.  If the library which has installed the callbacks is\n     * unloaded, then all bets are off. */\n    if (ID_CALLBACK_IS_OTHER || CRYPTO_get_locking_callback() != NULL) {\n        NE_DEBUG(NE_DBG_SOCKET, \"ssl: OpenSSL thread-safety callbacks already installed.\\n\");\n        NE_DEBUG(NE_DBG_SOCKET, \"ssl: neon will not replace existing callbacks.\\n\");\n    } else {\n        size_t n;\n\n        num_locks = CRYPTO_num_locks();\n\n        /* For releases where CRYPTO_set_idptr_callback is present,\n         * the default ID callback should be sufficient. */\n#ifndef HAVE_CRYPTO_SET_IDPTR_CALLBACK\n        CRYPTO_set_id_callback(thread_id_neon);\n#endif\n        CRYPTO_set_locking_callback(thread_lock_neon);\n\n        locks = malloc(num_locks * sizeof *locks);\n        for (n = 0; n < num_locks; n++) {\n#ifndef _WIN32\n            if (pthread_mutex_init(&locks[n], NULL)) {\n#else\n            if ((locks[n] = CreateMutex(NULL, FALSE, NULL)) == NULL) {\n#endif\n                NE_DEBUG(NE_DBG_SOCKET, \"ssl: Failed to initialize pthread mutex.\\n\");\n                return -1;\n            }\n        }\n        \n        NE_DEBUG(NE_DBG_SOCKET, \"ssl: Initialized OpenSSL thread-safety callbacks \"\n                 \"for %\" NE_FMT_SIZE_T \" locks.\\n\", num_locks);\n    }\n#endif\n#endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */\n\n    return 0;\n}\n\nvoid ne__ssl_exit(void)\n{\n    /* Cannot call ERR_free_strings() etc here in case any other code\n     * in the process using OpenSSL. */\n\n#ifdef WITH_OPENSSL_LOCKING\n    /* Only unregister the callbacks if some *other* library has not\n     * come along in the mean-time and trampled over the callbacks\n     * installed by neon. */\n    if (CRYPTO_get_locking_callback() == thread_lock_neon\n        && ID_CALLBACK_IS_NEON) {\n        size_t n;\n\n#ifndef HAVE_CRYPTO_SET_IDPTR_CALLBACK\n        CRYPTO_set_id_callback(NULL);\n#endif\n        CRYPTO_set_locking_callback(NULL);\n\n        for (n = 0; n < num_locks; n++) {\n#ifndef _WIN32\n            pthread_mutex_destroy(&locks[n]);\n#else\n            CloseHandle(locks[n]);\n#endif\n        }\n\n        free(locks);\n    }\n#endif\n}\n"
  },
  {
    "path": "src/ne_pkcs11.c",
    "content": "/*\n   neon PKCS#11 support\n   Copyright (C) 2021, Joe Orton <joe@manyfish.co.uk>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n\n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n*/\n\n#include \"config.h\"\n\n#include \"ne_pkcs11.h\"\n\n#ifdef HAVE_PAKCHOIS\n#include <string.h>\n#include <assert.h>\n\n#include <pakchois.h>\n\n#include \"ne_internal.h\"\n#include \"ne_alloc.h\"\n#include \"ne_private.h\"\n#include \"ne_privssl.h\"\n\nstruct ne_ssl_pkcs11_provider_s {\n    pakchois_module_t *module;\n    ne_ssl_pkcs11_pin_fn pin_fn;\n    void *pin_data;\n    pakchois_session_t *session;\n    ne_ssl_client_cert *clicert;\n    ck_object_handle_t privkey;\n    ck_key_type_t keytype;\n#ifdef HAVE_OPENSSL\n    RSA_METHOD *method;\n#endif\n};\n\n/* To do list for PKCS#11 support:\n\n   - propagate error strings back to ne_session; use new \n   pakchois_error() for pakchois API 0.2\n   - add API to specify a particular slot number to use for clicert\n   - add API to specify a particular cert ID for clicert\n   - find a certificate which has an issuer matching the \n     CA dnames given by GnuTLS\n   - make sure subject name matches between pubkey and privkey\n   - check error handling & fail gracefully if the token is \n   ejected mid-session\n   - add API to enumerate/search provided certs and allow \n     direct choice? (or just punt)\n   - the session<->provider interface requires that \n   one clicert is used for all sessions.  remove this limitation\n   - add API to import all CA certs as trusted\n   (CKA_CERTIFICATE_CATEGORY seems to be unused unfortunately; \n    just add all X509 certs with CKA_TRUSTED set to true))\n   - make DSA work\n\n*/\n\n#ifdef HAVE_OPENSSL\n\n#include <openssl/rsa.h>\n#include <openssl/err.h>\n\n#if defined(RSA_F_RSA_OSSL_PRIVATE_ENCRYPT)\n#define PK11_RSA_ERR (RSA_F_RSA_OSSL_PRIVATE_ENCRYPT)\n#else\n#define PK11_RSA_ERR (RSA_F_RSA_EAY_PRIVATE_ENCRYPT)\n#endif\n\n#if OPENSSL_VERSION_NUMBER < 0x10100000L\n/* Compatibility functions for OpenSSL < 1.1.0: */\n#define RSA_meth_get0_app_data(rsa) (void *)(rsa->app_data)\nstatic RSA_METHOD *RSA_meth_new(const char *name, int flags)\n{\n    RSA_METHOD *m = ne_calloc(sizeof *m);\n\n    m->name = name;\n    m->flags = flags;\n\n    return m;\n\n}\n#define RSA_meth_free ne_free\n#define RSA_meth_set_priv_enc(m, f) (m)->rsa_priv_enc = (f)\n#define RSA_meth_set0_app_data(m, f) (m)->app_data = (void *)(f)\n#endif\n\n/* RSA_METHOD ->rsa_private_encrypt callback. */\nstatic int pk11_rsa_encrypt(int mlen, const unsigned char *m, \n                            unsigned char *sigret,\n                            RSA *r, int padding)\n{\n    const RSA_METHOD *method = RSA_get_method(r);\n    ne_ssl_pkcs11_provider *prov = RSA_meth_get0_app_data(method);\n    ck_rv_t rv;\n    struct ck_mechanism mech;\n    unsigned long len;\n\n    if (!prov->session || prov->privkey == CK_INVALID_HANDLE) {\n        NE_DEBUG(NE_DBG_SSL, \"pk11: Cannot sign, no session/key.\\n\");\n        RSAerr(PK11_RSA_ERR,ERR_R_RSA_LIB);\n        return 0;\n    }\n\n    if (padding != RSA_PKCS1_PADDING && padding != RSA_NO_PADDING) {\n        NE_DEBUG(NE_DBG_SSL, \"pk11: Cannot sign, unknown padding mode '%d'.\\n\", padding);\n        RSAerr(PK11_RSA_ERR,ERR_R_RSA_LIB);\n        return 0;\n    }        \n\n    mech.mechanism = padding == RSA_PKCS1_PADDING ? CKM_RSA_PKCS : CKM_RSA_X_509;\n    mech.parameter = NULL;\n    mech.parameter_len = 0;\n\n    /* Initialize signing operation; using the private key discovered\n     * earlier. */\n    rv = pakchois_sign_init(prov->session, &mech, prov->privkey);\n    if (rv != CKR_OK) {\n        NE_DEBUG(NE_DBG_SSL, \"pk11: SignInit failed: %lx.\\n\", rv);\n        RSAerr(PK11_RSA_ERR, ERR_R_RSA_LIB);\n        return 0;\n    }\n\n    len = RSA_size(r);\n    rv = pakchois_sign(prov->session, (unsigned char *)m, mlen, sigret, &len);\n    if (rv != CKR_OK) {\n        NE_DEBUG(NE_DBG_SSL, \"pk11: Sign failed.\\n\");\n        RSAerr(PK11_RSA_ERR, ERR_R_RSA_LIB);\n        return 0;\n    }\n\n    NE_DEBUG(NE_DBG_SSL, \"pk11: Signed successfully.\\n\");\n    return len;\n}\n\n/* Return an RSA_METHOD which will use the PKCS#11 provider to\n * implement the signing operation. */\nstatic RSA_METHOD *pk11_rsa_method(ne_ssl_pkcs11_provider *prov)\n{\n    RSA_METHOD *m = RSA_meth_new(\"neon PKCS#11\", RSA_METHOD_FLAG_NO_CHECK);\n\n    RSA_meth_set_priv_enc(m, pk11_rsa_encrypt);\n    RSA_meth_set0_app_data(m, prov);\n\n    return m;\n}\n#endif\n\n#ifdef HAVE_GNUTLS\nstatic int pk11_sign_callback(gnutls_privkey_t pkey,\n                              void *userdata,\n                              const gnutls_datum_t *raw_data,\n                              gnutls_datum_t *signature);\n#endif\n\nstatic int pk11_find_x509(ne_ssl_pkcs11_provider *prov,\n                          pakchois_session_t *pks, \n                          unsigned char *certid, unsigned long *cid_len)\n{\n    struct ck_attribute a[3];\n    ck_object_class_t class;\n    ck_certificate_type_t type;\n    ck_rv_t rv;\n    ck_object_handle_t obj;\n    unsigned long count;\n    int found = 0;\n\n    /* Find objects with cert class and X.509 cert type. */\n    class = CKO_CERTIFICATE;\n    type = CKC_X_509;\n\n    a[0].type = CKA_CLASS;\n    a[0].value = &class;\n    a[0].value_len = sizeof class;\n    a[1].type = CKA_CERTIFICATE_TYPE;\n    a[1].value = &type;\n    a[1].value_len = sizeof type;\n\n    rv = pakchois_find_objects_init(pks, a, 2);\n    if (rv != CKR_OK) {\n        NE_DEBUG(NE_DBG_SSL, \"pk11: FindObjectsInit failed.\\n\");\n        return 0;\n    }\n\n    while (pakchois_find_objects(pks, &obj, 1, &count) == CKR_OK\n           && count == 1) {\n        unsigned char value[8192], subject[8192];\n\n        a[0].type = CKA_VALUE;\n        a[0].value = value;\n        a[0].value_len = sizeof value;\n        a[1].type = CKA_ID;\n        a[1].value = certid;\n        a[1].value_len = *cid_len;\n        a[2].type = CKA_SUBJECT;\n        a[2].value = subject;\n        a[2].value_len = sizeof subject;\n\n        if (pakchois_get_attribute_value(pks, obj, a, 3) == CKR_OK) {\n            ne_ssl_client_cert *cc;\n            \n#ifdef HAVE_GNUTLS\n            cc = ne__ssl_clicert_exkey_import(value, a[0].value_len, pk11_sign_callback, prov);\n#else\n            cc = ne__ssl_clicert_exkey_import(value, a[0].value_len, prov->method);\n#endif\n            if (cc) {\n                NE_DEBUG(NE_DBG_SSL, \"pk11: Imported X.509 cert.\\n\");\n                prov->clicert = cc;\n                found = 1;\n                *cid_len = a[1].value_len;\n                break;\n            }\n        }\n        else {\n            NE_DEBUG(NE_DBG_SSL, \"pk11: Skipped cert, missing attrs.\\n\");\n        }\n    }\n\n    pakchois_find_objects_final(pks);\n    return found;    \n}\n\n#ifdef HAVE_OPENSSL\n/* No DSA support for OpenSSL (yet, anyway). */\n#define KEYTYPE_IS_DSA(kt) (0)\n#else\n#define KEYTYPE_IS_DSA(kt) (kt == CKK_DSA)\n#endif\n\nstatic int pk11_find_pkey(ne_ssl_pkcs11_provider *prov, \n                          pakchois_session_t *pks,\n                          unsigned char *certid, unsigned long cid_len)\n{\n    struct ck_attribute a[3];\n    ck_object_class_t class;\n    ck_rv_t rv;\n    ck_object_handle_t obj;\n    unsigned long count;\n    int found = 0;\n\n    class = CKO_PRIVATE_KEY;\n\n    /* Find an object with private key class and a certificate ID\n     * which matches the certificate. */\n    /* FIXME: also match the cert subject. */\n    a[0].type = CKA_CLASS;\n    a[0].value = &class;\n    a[0].value_len = sizeof class;\n    a[1].type = CKA_ID;\n    a[1].value = certid;\n    a[1].value_len = cid_len;\n\n    rv = pakchois_find_objects_init(pks, a, 2);\n    if (rv != CKR_OK) {\n        NE_DEBUG(NE_DBG_SSL, \"pk11: FindObjectsInit failed.\\n\");\n        /* TODO: error propagation */\n        return 0;\n    }\n\n    rv = pakchois_find_objects(pks, &obj, 1, &count);\n    if (rv == CKR_OK && count == 1) {\n        NE_DEBUG(NE_DBG_SSL, \"pk11: Found private key.\\n\");\n\n        a[0].type = CKA_KEY_TYPE;\n        a[0].value = &prov->keytype;\n        a[0].value_len = sizeof prov->keytype;\n\n        if (pakchois_get_attribute_value(pks, obj, a, 1) == CKR_OK\n            && (prov->keytype == CKK_RSA || KEYTYPE_IS_DSA(prov->keytype))) {\n            found = 1;\n            prov->privkey = obj;\n        }\n        else {\n            NE_DEBUG(NE_DBG_SSL, \"pk11: Could not determine key type.\\n\");\n        }\n    }\n\n    pakchois_find_objects_final(pks);\n\n    return found;\n}\n\nstatic int find_client_cert(ne_ssl_pkcs11_provider *prov,\n                            pakchois_session_t *pks)\n{\n    unsigned char certid[8192];\n    unsigned long cid_len = sizeof certid;\n\n    /* TODO: match cert subject too. */\n    return pk11_find_x509(prov, pks, certid, &cid_len) \n        && pk11_find_pkey(prov, pks, certid, cid_len);\n}\n\n#ifdef HAVE_GNUTLS\n/* Callback invoked by GnuTLS to provide the signature.  The signature\n * operation is handled here by the PKCS#11 provider.  */\nstatic int pk11_sign_callback(gnutls_privkey_t pkey,\n                              void *userdata,\n                              const gnutls_datum_t *hash,\n                              gnutls_datum_t *signature)\n{\n    ne_ssl_pkcs11_provider *prov = userdata;\n    ck_rv_t rv;\n    struct ck_mechanism mech;\n    unsigned long siglen;\n\n    if (!prov->session || prov->privkey == CK_INVALID_HANDLE) {\n        NE_DEBUG(NE_DBG_SSL, \"pk11: Cannot sign, no session/key.\\n\");\n        return GNUTLS_E_NO_CERTIFICATE_FOUND;\n    }\n\n    mech.mechanism = prov->keytype == CKK_DSA ? CKM_DSA : CKM_RSA_PKCS;\n    mech.parameter = NULL;\n    mech.parameter_len = 0;\n\n    /* Initialize signing operation; using the private key discovered\n     * earlier. */\n    rv = pakchois_sign_init(prov->session, &mech, prov->privkey);\n    if (rv != CKR_OK) {\n        NE_DEBUG(NE_DBG_SSL, \"pk11: SignInit failed: %lx.\\n\", rv);\n        return GNUTLS_E_PK_SIGN_FAILED;\n    }\n\n    /* Work out how long the signature must be: */\n    rv = pakchois_sign(prov->session, hash->data, hash->size, NULL, &siglen);\n    if (rv != CKR_OK) {\n        NE_DEBUG(NE_DBG_SSL, \"pk11: Sign1 failed.\\n\");\n        return GNUTLS_E_PK_SIGN_FAILED;\n    }\n\n    signature->data = gnutls_malloc(siglen);\n    signature->size = siglen;\n\n    rv = pakchois_sign(prov->session, hash->data, hash->size, \n                       signature->data, &siglen);\n    if (rv != CKR_OK) {\n        NE_DEBUG(NE_DBG_SSL, \"pk11: Sign2 failed.\\n\");\n        return GNUTLS_E_PK_SIGN_FAILED;\n    }\n\n    NE_DEBUG(NE_DBG_SSL, \"pk11: Signed successfully.\\n\");\n\n    return 0;\n}\n#endif\n\nstatic void terminate_string(unsigned char *str, size_t len)\n{\n    unsigned char *ptr = str + len - 1;\n\n    assert(len > 0);\n\n    while ((*ptr == ' ' || *ptr == '\\t' || *ptr == '\\0') && ptr >= str)\n        ptr--;\n    \n    if (ptr == str + len - 1)\n        str[len-1] = '\\0';\n    else\n        ptr[1] = '\\0';\n}\n\nstatic int pk11_login(ne_ssl_pkcs11_provider *prov, ck_slot_id_t slot_id,\n                      pakchois_session_t *pks, struct ck_slot_info *sinfo)\n{\n    struct ck_token_info tinfo;\n    int attempt = 0;\n    ck_rv_t rv;\n\n    if (pakchois_get_token_info(prov->module, slot_id, &tinfo) != CKR_OK) {\n        NE_DEBUG(NE_DBG_SSL, \"pk11: GetTokenInfo failed\\n\");\n        /* TODO: propagate error. */\n        return -1;\n    }\n\n    if ((tinfo.flags & CKF_LOGIN_REQUIRED) == 0) {\n        NE_DEBUG(NE_DBG_SSL, \"pk11: No login required.\\n\");\n        return 0;\n    }\n\n    /* For a token with a \"protected\" (out-of-band) authentication\n     * path, calling login with a NULL username is all that is\n     * required. */\n    if (tinfo.flags & CKF_PROTECTED_AUTHENTICATION_PATH) {\n        if (pakchois_login(pks, CKU_USER, NULL, 0) == CKR_OK) {\n            return 0;\n        }\n        else {\n            NE_DEBUG(NE_DBG_SSL, \"pk11: Protected login failed.\\n\");\n            /* TODO: error propagation. */\n            return -1;\n        }\n    }\n\n    /* Otherwise, PIN entry is necessary for login, so fail if there's\n     * no callback. */\n    if (!prov->pin_fn) {\n        NE_DEBUG(NE_DBG_SSL, \"pk11: No pin callback but login required.\\n\");\n        /* TODO: propagate error. */\n        return -1;\n    }\n\n    terminate_string(sinfo->slot_description, sizeof sinfo->slot_description);\n\n    do {\n        char pin[NE_SSL_P11PINLEN];\n        unsigned int flags = 0;\n\n        /* If login has been attempted once already, check the token\n         * status again, the flags might change. */\n        if (attempt) {\n            if (pakchois_get_token_info(prov->module, slot_id, \n                                        &tinfo) != CKR_OK) {\n                NE_DEBUG(NE_DBG_SSL, \"pk11: GetTokenInfo failed\\n\");\n                /* TODO: propagate error. */\n                return -1;\n            }\n        }\n\n        if (tinfo.flags & CKF_USER_PIN_COUNT_LOW)\n            flags |= NE_SSL_P11PIN_COUNT_LOW;\n        if (tinfo.flags & CKF_USER_PIN_FINAL_TRY)\n            flags |= NE_SSL_P11PIN_FINAL_TRY;\n        \n        terminate_string(tinfo.label, sizeof tinfo.label);\n\n        if (prov->pin_fn(prov->pin_data, attempt++,\n                         (char *)sinfo->slot_description,\n                         (char *)tinfo.label, flags, pin)) {\n            return -1;\n        }\n\n        rv = pakchois_login(pks, CKU_USER, (unsigned char *)pin, strlen(pin));\n        \n        ne__strzero(pin, sizeof pin);\n    } while (rv == CKR_PIN_INCORRECT);\n\n    NE_DEBUG(NE_DBG_SSL, \"pk11: Login result = %lu\\n\", rv);\n\n    return (rv == CKR_OK || rv == CKR_USER_ALREADY_LOGGED_IN) ? 0 : -1;\n}\n\nstatic void pk11_provide(void *userdata, ne_session *sess,\n                         const ne_ssl_dname *const *dnames,\n                         int dncount)\n{\n    ne_ssl_pkcs11_provider *prov = userdata;\n    ck_slot_id_t *slots;\n    unsigned long scount, n;\n\n    if (prov->clicert) {\n        NE_DEBUG(NE_DBG_SSL, \"pk11: Using existing clicert.\\n\");\n        ne_ssl_set_clicert(sess, prov->clicert);\n        return;\n    }\n\n    if (pakchois_get_slot_list(prov->module, 1, NULL, &scount) != CKR_OK\n        || scount == 0) {\n        NE_DEBUG(NE_DBG_SSL, \"pk11: No slots.\\n\");\n        /* TODO: propagate error. */\n        return;\n    }\n\n    slots = ne_malloc(scount * sizeof *slots);\n    if (pakchois_get_slot_list(prov->module, 1, slots, &scount) != CKR_OK)  {\n        ne_free(slots);\n        NE_DEBUG(NE_DBG_SSL, \"pk11: Really, no slots?\\n\");\n        /* TODO: propagate error. */\n        return;\n    }\n\n    NE_DEBUG(NE_DBG_SSL, \"pk11: Found %ld slots.\\n\", scount);\n\n    for (n = 0; n < scount; n++) {\n        pakchois_session_t *pks;\n        ck_rv_t rv;\n        struct ck_slot_info sinfo;\n\n        if (pakchois_get_slot_info(prov->module, slots[n], &sinfo) != CKR_OK) {\n            NE_DEBUG(NE_DBG_SSL, \"pk11: GetSlotInfo failed\\n\");\n            continue;\n        }\n\n        if ((sinfo.flags & CKF_TOKEN_PRESENT) == 0) {\n            NE_DEBUG(NE_DBG_SSL, \"pk11: slot empty, ignoring\\n\");\n            continue;\n        }\n        \n        rv = pakchois_open_session(prov->module, slots[n], \n                                   CKF_SERIAL_SESSION,\n                                   NULL, NULL, &pks);\n        if (rv != CKR_OK) {\n            NE_DEBUG(NE_DBG_SSL, \"pk11: could not open slot, %ld (%ld: %ld)\\n\", \n                     rv, n, slots[n]);\n            continue;\n        }\n\n        if (pk11_login(prov, slots[n], pks, &sinfo) == 0) {\n            if (find_client_cert(prov, pks)) {\n                NE_DEBUG(NE_DBG_SSL, \"pk11: Setup complete.\\n\");\n                prov->session = pks;\n                ne_ssl_set_clicert(sess, prov->clicert);\n                ne_free(slots);\n                return;\n            }\n        }\n\n        pakchois_close_session(pks);\n    }\n\n    ne_free(slots);\n}\n\nstatic int pk11_init(ne_ssl_pkcs11_provider **provider,\n                     pakchois_module_t *module)\n{\n    ne_ssl_pkcs11_provider *prov;\n\n    prov = *provider = ne_calloc(sizeof *prov);\n    prov->module = module;\n    prov->privkey = CK_INVALID_HANDLE;\n\n#ifdef HAVE_OPENSSL\n    prov->method = pk11_rsa_method(prov);\n#endif    \n    \n    return NE_PK11_OK;\n}\n\nint ne_ssl_pkcs11_provider_init(ne_ssl_pkcs11_provider **provider,\n                                const char *name)\n{\n    pakchois_module_t *pm;\n    \n    if (pakchois_module_load(&pm, name) == CKR_OK) {\n        return pk11_init(provider, pm);\n    }\n    else {\n        return NE_PK11_FAILED;\n    }\n}\n\nint ne_ssl_pkcs11_nss_provider_init(ne_ssl_pkcs11_provider **provider,\n                                    const char *name, const char *directory,\n                                    const char *cert_prefix, \n                                    const char *key_prefix,\n                                    const char *secmod_db)\n{\n    pakchois_module_t *pm;\n    \n    if (pakchois_module_nssload(&pm, name, directory, cert_prefix,\n                                key_prefix, secmod_db) == CKR_OK) {\n        return pk11_init(provider, pm);\n    }\n    else {\n        return NE_PK11_FAILED;\n    }\n}\n\nvoid ne_ssl_pkcs11_provider_pin(ne_ssl_pkcs11_provider *provider,\n                                ne_ssl_pkcs11_pin_fn fn,\n                                void *userdata)\n{\n    provider->pin_fn = fn;\n    provider->pin_data = userdata;\n}\n\nvoid ne_ssl_set_pkcs11_provider(ne_session *sess, \n                                ne_ssl_pkcs11_provider *provider)\n{\n    ne_ssl_provide_clicert(sess, pk11_provide, provider);\n}\n\nvoid ne_ssl_pkcs11_provider_destroy(ne_ssl_pkcs11_provider *prov)\n{\n    if (prov->session) {\n        pakchois_close_session(prov->session);\n    }\n    if (prov->clicert) {\n        ne_ssl_clicert_free(prov->clicert);\n    }\n    pakchois_module_destroy(prov->module);\n#ifdef HAVE_OPENSSL\n    RSA_meth_free(prov->method);\n#endif\n    ne_free(prov);\n}\n\n#else /* !HAVE_PAKCHOIS */\n\nint ne_ssl_pkcs11_provider_init(ne_ssl_pkcs11_provider **provider,\n                                const char *name)\n{\n    return NE_PK11_NOTIMPL;\n}\n\nint ne_ssl_pkcs11_nss_provider_init(ne_ssl_pkcs11_provider **provider,\n                                    const char *name, const char *directory,\n                                    const char *cert_prefix, \n                                    const char *key_prefix,\n                                    const char *secmod_db)\n{\n    return NE_PK11_NOTIMPL;\n}\n\nvoid ne_ssl_pkcs11_provider_destroy(ne_ssl_pkcs11_provider *provider) { }\n\nvoid ne_ssl_pkcs11_provider_pin(ne_ssl_pkcs11_provider *provider,\n                                ne_ssl_pkcs11_pin_fn fn,\n                                void *userdata) { }\n\nvoid ne_ssl_set_pkcs11_provider(ne_session *sess,\n                                ne_ssl_pkcs11_provider *provider) { }\n\n#endif /* HAVE_PAKCHOIS */\n\n"
  },
  {
    "path": "src/ne_pkcs11.h",
    "content": "/* \n   PKCS#11 support for neon\n   Copyright (C) 2008-2021, Joe Orton <joe@manyfish.co.uk>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n   \n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n\n#ifndef NE_PKCS11_H\n#define NE_PKCS11_H 1\n\n#include \"ne_defs.h\"\n#include \"ne_session.h\"\n\nNE_BEGIN_DECLS\n\n/*\n * DEPRECATED PKCS#11 interface. Use ne_ssl_clicert_fromuri() instead.\n */\n\ntypedef struct ne_ssl_pkcs11_provider_s ne_ssl_pkcs11_provider;\n\n#define NE_PK11_OK (0)\n#define NE_PK11_NOTIMPL (-1)\n#define NE_PK11_FAILED (-2)\n\n/* Initialize a PKCS#11 provider of given name.  Returns NE_OK on\n * success, NE_PK11_FAILED if the provider could not be\n * loaded/initialized, and NE_PK11_NOTIMPL if PKCS#11 is not\n * supported.  On success, *provider is set to non-NULL.  */\nint ne_ssl_pkcs11_provider_init(ne_ssl_pkcs11_provider **provider,\n                                const char *name);\n\n/* Initialize a NSS softoken pseudo-PKCS#11 provider of given name\n * (e.g. \"softokn3\") to supply a client certificate if requested,\n * using database in given directory name; the other parameters may be\n * NULL.  Returns NE_OK on success, NE_PK11_FAILED if the provider\n * could not be loaded/initialized, and NE_PK11_NOTIMPL if PKCS#11 is\n * not supported.  On success, *provider is set to non-NULL. */\nint ne_ssl_pkcs11_nss_provider_init(ne_ssl_pkcs11_provider **provider,\n                                    const char *name, const char *directory,\n                                    const char *cert_prefix, \n                                    const char *key_prefix,\n                                    const char *secmod_db);\n\n/* Destroy a PKCS#11 provider object. */\nvoid ne_ssl_pkcs11_provider_destroy(ne_ssl_pkcs11_provider *provider);\n\n\n/* Flags passed to PIN entry callback: */\n#define NE_SSL_P11PIN_COUNT_LOW (0x01) /* an incorrect PIN has been\n                                        * entered. */\n#define NE_SSL_P11PIN_FINAL_TRY (0x02) /* token will become locked if\n                                        * entered PIN is incorrect */\n\n/* Size of buffer passed to PIN entry callback: */\n#define NE_SSL_P11PINLEN (256)\n\n/* Callback for PKCS#11 PIN entry.  The callback provides the PIN code\n * to unlock the token with label 'token_label' in the slot described\n * by 'slot_descr'.\n *\n * The PIN code, as a NUL-terminated ASCII string, should be copied\n * into the 'pin' buffer (of fixed length NE_SSL_P11PINLEN), and\n * return 0 to indicate success. Alternatively, the callback may\n * return -1 to indicate failure and cancel PIN entry (in which case,\n * the contents of the 'pin' parameter are ignored).\n *\n * When a PIN is required, the callback will be invoked repeatedly\n * (and indefinitely) until either the returned PIN code is correct,\n * the callback returns failure, or the token refuses login (e.g. when\n * the token is locked due to too many incorrect PINs!).  For the\n * first such invocation, the 'attempt' counter will have value zero;\n * it will increase by one for each subsequent attempt.\n *\n * The NE_SSL_P11PIN_COUNT_LOW and/or NE_SSL_P11PIN_FINAL_TRY hints\n * may be set in the 'flags' argument, if these hints are made\n * available by the token; not all tokens expose these hints. */\ntypedef int (*ne_ssl_pkcs11_pin_fn)(void *userdata, int attempt,\n                                    const char *slot_descr,\n                                    const char *token_label,\n                                    unsigned int flags,\n                                    char *pin);\n\n/* Set the PIN entry callback for the given provider.  This is\n * necessary for some (but not all) types of token.  For tokens which\n * implement an out-of-band (\"protected\") authentication path, the PIN\n * entry callback will not be invoked. */\nvoid ne_ssl_pkcs11_provider_pin(ne_ssl_pkcs11_provider *provider,\n                                ne_ssl_pkcs11_pin_fn fn,\n                                void *userdata);\n\n/* Set up a given PKCS#11 provider to supply an appropriate client\n * certificate if requested by the server.  A provider may be\n * configured for use in multiple sessions. */\nvoid ne_ssl_set_pkcs11_provider(ne_session *sess,\n                                ne_ssl_pkcs11_provider *provider);\n\nNE_END_DECLS\n\n#endif /* NE_PKCS11_H */\n"
  },
  {
    "path": "src/ne_private.h",
    "content": "/* \n   HTTP Request Handling\n   Copyright (C) 1999-2021, Joe Orton <joe@manyfish.co.uk>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n   \n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n\n/* THIS IS NOT A PUBLIC INTERFACE. You CANNOT include this header file\n * from an application.  */\n \n#ifndef NE_PRIVATE_H\n#define NE_PRIVATE_H\n\n#include \"ne_request.h\"\n#include \"ne_socket.h\"\n#include \"ne_ssl.h\"\n\nstruct host_info {\n    /* Type of host represented: */\n    enum proxy_type {\n        PROXY_NONE = 0,\n        PROXY_HTTP, /* an HTTP proxy */\n        PROXY_SOCKS /* a SOCKS proxy */\n    } proxy;\n    unsigned int port;\n    /* If hostname is non-NULL, host is identified by this hostname. */\n    char *hostname, *hostport;\n    /* If address is non-NULL, the result of resolving ->hostname. */\n    ne_sock_addr *address;\n    /* If current non-NULL, current network address used in ->address. */\n    const ne_inet_addr *current;\n    /* If override is non-NULL, the host is identified by this network\n     * address. */\n    const ne_inet_addr *network;\n    /* Result of a literal string IP address lookup. */\n    ne_inet_addr *literal;\n    struct host_info *next;\n};\n\n/* Store every registered callback in a generic container, and cast\n * the function pointer when calling it.  */\nstruct hook {\n    void (*fn)(void);\n    void *userdata;\n    const char *id; /* non-NULL for accessors. */\n    struct hook *next;\n};\n\n#define HAVE_HOOK(st,func) (st->hook->hooks->func != NULL)\n#define HOOK_FUNC(st, func) (*st->hook->hooks->func)\n\n/* Session support. */\nstruct ne_session_s {\n    /* Connection information */\n    ne_socket *socket;\n\n    /* non-zero if connection has been established. */\n    int connected;\n    \n    /* non-zero if connection has persisted beyond one request. */\n    int persisted;\n\n    int is_http11; /* >0 if connected server is known to be\n\t\t    * HTTP/1.1 compliant. */\n\n    char *scheme;\n\n    /* Server host details. */\n    struct host_info server;\n    /* Proxy host details, or NULL if not using a proxy. */\n    struct host_info *proxies;\n    /* Most recently used proxy server. */\n    struct host_info *prev_proxy;\n\n    /* Pointer to the active .server or .proxies as appropriate: */\n    const struct host_info *nexthop;\n\n    /* Local address to which sockets should be bound. */\n    const ne_inet_addr *local_addr;\n\n    /* Settings */\n    int use_ssl; /* whether a secure connection is required */\n    int in_connect; /* doing a proxy CONNECT */\n    int any_proxy_http; /* whether any configured proxy is an HTTP proxy */\n    \n    enum ne_sock_sversion socks_ver;\n    char *socks_user, *socks_password;\n\n    int flags[NE_SESSFLAG_LAST];\n\n    ne_progress progress_cb;\n    void *progress_ud;\n\n    ne_notify_status notify_cb;\n    void *notify_ud;\n\n    int rdtimeout, cotimeout; /* read, connect timeouts. */\n\n    struct hook *create_req_hooks, *pre_send_hooks, *post_send_hooks,\n        *post_headers_hooks, *destroy_req_hooks, *destroy_sess_hooks, \n        *close_conn_hooks, *private;\n\n    char *user_agent; /* full User-Agent: header field */\n\n#ifdef NE_HAVE_SSL\n    ne_ssl_certificate *server_cert;\n    ne_ssl_context *ssl_context;\n\n    /* Client cert provider callback: */\n    ne_ssl_provide_fn ssl_provide_fn;\n    void *ssl_provide_ud;\n#endif\n\n    /* Server cert verification callback: */\n    ne_ssl_verify_fn ssl_verify_fn;\n    void *ssl_verify_ud;\n\n    ne_session_status_info status;\n\n    /* Error string */\n    char error[512];\n};\n\n/* Pushes block of 'count' bytes at 'buf'. Returns non-zero on\n * error. */\ntypedef int (*ne_push_fn)(void *userdata, const char *buf, size_t count);\n\n/* Do the SSL negotiation. */\nNE_PRIVATE int ne__negotiate_ssl(ne_session *sess);\n\n#endif /* HTTP_PRIVATE_H */\n"
  },
  {
    "path": "src/ne_privssl.h",
    "content": "/* \n   SSL interface definitions internal to neon.\n   Copyright (C) 2003-2021, Joe Orton <joe@manyfish.co.uk>\n   Copyright (C) 2004, Aleix Conchillo Flaque <aleix@member.fsf.org>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n   \n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n\n/* THIS IS NOT A PUBLIC INTERFACE. You CANNOT include this header file\n * from an application.  */\n \n#ifndef NE_PRIVSSL_H\n#define NE_PRIVSSL_H\n\n/* This is the private interface between ne_socket, ne_gnutls and\n * ne_openssl. */\n\n#include \"ne_ssl.h\"\n#include \"ne_socket.h\"\n\n#ifdef HAVE_OPENSSL\n\n#include <openssl/ssl.h>\n\nstruct ne_ssl_context_s {\n    SSL_CTX *ctx;\n    SSL_SESSION *sess;\n    const char *hostname; /* for SNI */\n    ne_ssl_client_cert *client_cert;\n    ne_ssl_ccprovide_fn provider;\n    void *provider_ud;\n};\n\ntypedef struct ne_ssl_socket_s {\n    SSL *ssl;\n    int failures;\n    /* set to non-zero if a client cert was requested during initial\n     * handshake, but none could be provided. */\n    int cc_requested;\n} ne_ssl_socket;\n\nNE_PRIVATE ne_ssl_socket *ne__sock_sslsock(ne_socket *sock);\n\n/* Create a clicert object from cert DER {der, der_len}, using given\n * RSA_METHOD for the RSA object. */\nNE_PRIVATE ne_ssl_client_cert *\nne__ssl_clicert_exkey_import(const unsigned char *der,\n                             size_t der_len,\n                             const RSA_METHOD *method);\n\nNE_PRIVATE ne_ssl_certificate *ne__ssl_make_chain(STACK_OF(X509) *chain);\n\n#endif /* HAVE_OPENSSL */\n\n#ifdef HAVE_GNUTLS\n\n#include <gnutls/gnutls.h>\n\n#ifdef HAVE_GNUTLS_PRIVKEY_IMPORT_EXT\n#include <gnutls/abstract.h>\n#endif\n\nstruct ne_ssl_context_s {\n    gnutls_certificate_credentials_t cred;\n    int verify; /* non-zero if client cert verification required */\n    ne_ssl_client_cert *client_cert;\n    const char *hostname; /* for SNI */\n    char *priority;\n\n    ne_ssl_ccprovide_fn provider;\n    void *provider_ud;\n\n    /* Session cache. */\n    union ne_ssl_scache {\n        struct {\n            gnutls_datum_t key, data;\n        } server;\n#if defined(HAVE_GNUTLS_SESSION_GET_DATA2)\n        gnutls_datum_t client;\n#else\n        struct {\n            char *data;\n            size_t len;\n        } client;\n#endif\n    } cache;\n};\n\ntypedef struct ne_ssl_socket_s {\n    gnutls_session_t sess;\n    ne_ssl_context *context;\n    /* set to non-zero if a client cert was requested during initial\n     * handshake, but none could be provided. */\n    int cc_requested;\n} ne_ssl_socket;\n\n#ifdef HAVE_GNUTLS_PRIVKEY_IMPORT_EXT\nNE_PRIVATE ne_ssl_client_cert *\nne__ssl_clicert_exkey_import(const unsigned char *der, size_t der_len,\n                             gnutls_privkey_sign_func sign_func, void *userdata);\n#endif\n\nNE_PRIVATE ne_ssl_certificate *ne__ssl_make_chain(gnutls_session_t sock,\n                                                  gnutls_certificate_credentials_t crd);\n\n#endif /* HAVE_GNUTLS */\n\n#ifdef NE_HAVE_SSL\n/* Set the socket error appropriate for SSL verification failures. */\nNE_PRIVATE void ne__sock_set_verify_err(ne_socket *sock, int failures);\n\n/* Process-global initialization of the SSL library; returns non-zero\n * on error. */\nNE_PRIVATE int ne__ssl_init(void);\n\n/* Process-global de-initialization of the SSL library. */\nNE_PRIVATE void ne__ssl_exit(void);\n\nNE_PRIVATE ne_ssl_socket *ne__sock_sslsock(ne_socket *sock);\n\n/* Return non-zero if hostname from certificate (cn) matches hostname\n * used for session (hostname); follows RFC2818 logic. */\nNE_PRIVATE int ne__ssl_match_hostname(const char *cn, size_t cnlen, \n                                      const char *hostname);\n#endif\n\n#endif /* NE_PRIVSSL_H */\n"
  },
  {
    "path": "src/ne_props.c",
    "content": "/* \n   WebDAV property manipulation\n   Copyright (C) 2000-2021, Joe Orton <joe@manyfish.co.uk>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n   \n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n\n#include \"config.h\"\n\n#ifdef HAVE_STDLIB_H\n#include <stdlib.h>\n#endif\n#ifdef HAVE_STRING_H\n#include <string.h>\n#endif\n\n#include \"ne_alloc.h\"\n#include \"ne_xmlreq.h\"\n#include \"ne_props.h\"\n#include \"ne_basic.h\"\n#include \"ne_locks.h\"\n#include \"ne_internal.h\"\n\n/* don't store flat props with a value > 10K */\n#define MAX_FLATPROP_LEN (102400)\n\nstruct ne_propfind_handler_s {\n    ne_session *sess;\n    ne_request *request;\n\n    int has_props; /* whether we've already written some\n\t\t    * props to the body. */\n    ne_buffer *body;\n    \n    ne_207_parser *parser207;\n    ne_xml_parser *parser;\n\n    /* Creator/destructor callbacks. */\n    ne_props_create_complex creator;\n    ne_props_destroy_complex destructor;\n    void *cd_userdata;\n    \n    /* Current propset, or NULL if none being processed. */\n    ne_prop_result_set *current;\n\n    ne_buffer *value; /* current flat property value */\n    int depth; /* nesting depth within a flat property */\n\n    ne_props_result callback;\n    void *userdata;\n};\n\n#define ELM_flatprop (NE_207_STATE_TOP - 1)\n\n/* We build up the results of one 'response' element in memory. */\nstruct prop {\n    char *name, *nspace, *value, *lang;\n    /* Store a ne_propname here too, for convenience.  pname.name =\n     * name, pname.nspace = nspace, but they are const'ed in pname. */\n    ne_propname pname;\n};\n\n#define NSPACE(x) ((x) ? (x) : \"\")\n\nstruct propstat {\n    struct prop *props;\n    int numprops;\n    ne_status status;\n};\n\n/* Results set. */\nstruct ne_prop_result_set_s {\n    struct propstat *pstats;\n    int numpstats, counter;\n    void *private;\n    ne_uri uri;\n};\n\n#define MAX_PROP_COUNTER (1024)\n\nstatic int \nstartelm(void *userdata, int state, const char *nspace, const char *name,\n\t const char **atts);\nstatic int \nendelm(void *userdata, int state, const char *nspace, const char *name);\n\n/* Handle character data; flat property value. */\nstatic int chardata(void *userdata, int state, const char *data, size_t len)\n{\n    ne_propfind_handler *hdl = userdata;\n\n    if (state == ELM_flatprop && hdl->value->length < MAX_FLATPROP_LEN)\n        ne_buffer_append(hdl->value, data, len);\n\n    return 0;\n}\n\nne_xml_parser *ne_propfind_get_parser(ne_propfind_handler *handler)\n{\n    return handler->parser;\n}\n\nne_request *ne_propfind_get_request(ne_propfind_handler *handler)\n{\n    return handler->request;\n}\n\nstatic int propfind(ne_propfind_handler *handler, \n\t\t    ne_props_result results, void *userdata)\n{\n    int ret;\n    ne_request *req = handler->request;\n\n    /* Register the flat property handler to catch any properties \n     * which the user isn't handling as 'complex'. */\n    ne_xml_push_handler(handler->parser, startelm, chardata, endelm, handler);\n\n    handler->callback = results;\n    handler->userdata = userdata;\n\n    ne_set_request_body_buffer(req, handler->body->data,\n\t\t\t       ne_buffer_size(handler->body));\n    ne_add_request_header(req, \"Content-Type\", NE_XML_MEDIA_TYPE);\n\n    ret = ne_xml_dispatchif_request(req, handler->parser, ne_accept_207, NULL);\n\n    if (ret == NE_OK && ne_get_status(req)->klass != 2) {\n\tret = NE_ERROR;\n    }\n\n    return ret;\n}\n\nstatic void set_body(ne_propfind_handler *hdl, const ne_propname *names)\n{\n    ne_buffer *body = hdl->body;\n    int n;\n    \n    if (!hdl->has_props) {\n\tne_buffer_czappend(body, \"<prop>\\n\");\n\thdl->has_props = 1;\n    }\n\n    for (n = 0; names[n].name != NULL; n++) {\n\tne_buffer_concat(body, \"<\", names[n].name, \" xmlns=\\\"\", \n\t\t\t NSPACE(names[n].nspace), \"\\\"/>\\n\", NULL);\n    }\n\n}\n\nint ne_propfind_allprop(ne_propfind_handler *handler, \n\t\t\t ne_props_result results, void *userdata)\n{\n    ne_buffer_czappend(handler->body, \"<allprop/></propfind>\\n\");\n    return propfind(handler, results, userdata);\n}\n\nint ne_propfind_named(ne_propfind_handler *handler, const ne_propname *props,\n\t\t       ne_props_result results, void *userdata)\n{\n    set_body(handler, props);\n    ne_buffer_czappend(handler->body, \"</prop></propfind>\\n\");\n    return propfind(handler, results, userdata);\n}\n\n\n/* The easy one... PROPPATCH */\nint ne_proppatch(ne_session *sess, const char *uri, \n\t\t const ne_proppatch_operation *items)\n{\n    ne_request *req = ne_request_create(sess, \"PROPPATCH\", uri);\n    ne_buffer *body = ne_buffer_create();\n    int n, ret;\n    \n    /* Create the request body */\n    ne_buffer_czappend(body, \"<?xml version=\\\"1.0\\\" encoding=\\\"utf-8\\\" ?>\\n\"\n                       \"<D:propertyupdate xmlns:D=\\\"DAV:\\\">\");\n\n    for (n = 0; items[n].name != NULL; n++) {\n\tconst char *elm = (items[n].type == ne_propset) ? \"set\" : \"remove\";\n\n\t/* <set><prop><prop-name>value</prop-name></prop></set> */\n\tne_buffer_concat(body, \"<D:\", elm, \"><D:prop>\"\n\t\t\t \"<\", items[n].name->name, NULL);\n\t\n\tif (items[n].name->nspace) {\n\t    ne_buffer_concat(body, \" xmlns=\\\"\", items[n].name->nspace, \"\\\"\", NULL);\n\t}\n\n\tif (items[n].type == ne_propset) {\n\t    ne_buffer_concat(body, \">\", items[n].value, NULL);\n\t} else {\n\t    ne_buffer_append(body, \">\", 1);\n\t}\n\n\tne_buffer_concat(body, \"</\", items[n].name->name, \"></D:prop></D:\", elm, \n                         \">\\n\", NULL);\n    }\t\n\n    ne_buffer_czappend(body, \"</D:propertyupdate>\\n\");\n\n    ne_set_request_body_buffer(req, body->data, ne_buffer_size(body));\n    ne_add_request_header(req, \"Content-Type\", NE_XML_MEDIA_TYPE);\n    \n#ifdef NE_HAVE_DAV\n    ne_lock_using_resource(req, uri, NE_DEPTH_ZERO);\n#endif\n\n    ret = ne_simple_request(sess, req);\n    \n    ne_buffer_destroy(body);\n\n    return ret;\n}\n\n/* Compare two property names. */\nstatic int pnamecmp(const ne_propname *pn1, const ne_propname *pn2)\n{\n    if (pn1->nspace == NULL && pn2->nspace != NULL) {\n\treturn 1;\n    } else if (pn1->nspace != NULL && pn2->nspace == NULL) {\n\treturn -1;\n    } else if (pn1->nspace == NULL) {\n\treturn strcmp(pn1->name, pn2->name);\n    } else {\n\treturn (strcmp(pn1->nspace, pn2->nspace) ||\n\t\tstrcmp(pn1->name, pn2->name));\n    }\n}\n\n/* Find property in 'set' with name 'pname'.  If found, set pstat_ret\n * to the containing propstat, likewise prop_ret, and returns zero.\n * If not found, returns non-zero.  */\nstatic int findprop(const ne_prop_result_set *set, const ne_propname *pname,\n\t\t    struct propstat **pstat_ret, struct prop **prop_ret)\n{\n    \n    int ps, p;\n\n    for (ps = 0; ps < set->numpstats; ps++) {\n\tfor (p = 0; p < set->pstats[ps].numprops; p++) {\n\t    struct prop *prop = &set->pstats[ps].props[p];\n\n\t    if (pnamecmp(&prop->pname, pname) == 0) {\n\t\tif (pstat_ret != NULL)\n\t\t    *pstat_ret = &set->pstats[ps];\n\t\tif (prop_ret != NULL)\n\t\t    *prop_ret = prop;\n\t\treturn 0;\n\t    }\n\t}\n    }\n\n    return -1;\n}\n\nconst char *ne_propset_value(const ne_prop_result_set *set,\n\t\t\t      const ne_propname *pname)\n{\n    struct prop *prop;\n    \n    if (findprop(set, pname, NULL, &prop)) {\n\treturn NULL;\n    } else {\n\treturn prop->value;\n    }\n}\n\nconst char *ne_propset_lang(const ne_prop_result_set *set,\n\t\t\t     const ne_propname *pname)\n{\n    struct prop *prop;\n\n    if (findprop(set, pname, NULL, &prop)) {\n\treturn NULL;\n    } else {\n\treturn prop->lang;\n    }\n}\n\nvoid *ne_propfind_current_private(ne_propfind_handler *handler)\n{\n    return handler->current ? handler->current->private : NULL;\n}\n\nvoid *ne_propset_private(const ne_prop_result_set *set)\n{\n    return set->private;\n}\n\nint ne_propset_iterate(const ne_prop_result_set *set,\n\t\t\tne_propset_iterator iterator, void *userdata)\n{\n    int ps, p;\n\n    for (ps = 0; ps < set->numpstats; ps++) {\n\tfor (p = 0; p < set->pstats[ps].numprops; p++) {\n\t    struct prop *prop = &set->pstats[ps].props[p];\n\t    int ret = iterator(userdata, &prop->pname, prop->value, \n\t\t\t       &set->pstats[ps].status);\n\t    if (ret)\n\t\treturn ret;\n\n\t}\n    }\n\n    return 0;\n}\n\nconst ne_status *ne_propset_status(const ne_prop_result_set *set,\n\t\t\t\t      const ne_propname *pname)\n{\n    struct propstat *pstat;\n    \n    if (findprop(set, pname, &pstat, NULL)) {\n\t/* TODO: it is tempting to return a dummy status object here\n\t * rather than NULL, which says \"Property result was not given\n\t * by server.\"  but I'm not sure if this is best left to the\n\t * client.  */\n\treturn NULL;\n    } else {\n\treturn &pstat->status;\n    }\n}\n\nstatic void *start_response(void *userdata, const ne_uri *uri)\n{\n    ne_prop_result_set *set = ne_calloc(sizeof(*set));\n    ne_propfind_handler *hdl = userdata;\n\n    ne_uri_copy(&set->uri, uri);\n\n    if (hdl->creator) {\n\tset->private = hdl->creator(hdl->cd_userdata, &set->uri);\n    }\n\n    hdl->current = set;\n\n    return set;\n}\n\nstatic void *start_propstat(void *userdata, void *response)\n{\n    ne_prop_result_set *set = response;\n    ne_propfind_handler *hdl = userdata;\n    struct propstat *pstat;\n    int n;\n\n    if (++hdl->current->counter == MAX_PROP_COUNTER) {\n        ne_xml_set_error(hdl->parser, _(\"Response exceeds maximum property count\"));\n        return NULL;\n    }\n    \n    n = set->numpstats;\n    set->pstats = ne_realloc(set->pstats, sizeof(struct propstat) * (n+1));\n    set->numpstats = n+1;\n\n    pstat = &set->pstats[n];\n    memset(pstat, 0, sizeof(*pstat));\n    \n    /* And return this as the new pstat. */\n    return &set->pstats[n];\n}\n\nstatic int startelm(void *userdata, int parent,\n                    const char *nspace, const char *name, const char **atts)\n{\n    ne_propfind_handler *hdl = userdata;\n    struct propstat *pstat = ne_207_get_current_propstat(hdl->parser207);\n    struct prop *prop;\n    int n;\n    const char *lang;\n\n    /* Just handle all children of propstat and their descendants. */\n    if ((parent != NE_207_STATE_PROP && parent != ELM_flatprop) \n        || pstat == NULL)\n        return NE_XML_DECLINE;\n\n    if (parent == ELM_flatprop) {\n        /* collecting the flatprop value. */\n        hdl->depth++;\n        if (hdl->value->used < MAX_FLATPROP_LEN) {\n            const char **a = atts;\n\n            ne_buffer_concat(hdl->value, \"<\", nspace, name, NULL);\n            \n            while (a[0] && hdl->value->used < MAX_FLATPROP_LEN) {\n                const char *nsep = strchr(a[0], ':'), *pfx;\n\n                /* Resolve the attribute namespace prefix, if any.\n                 * Ignore a failure to resolve the namespace prefix. */\n                pfx = nsep ? ne_xml_resolve_nspace(hdl->parser,\n                                                   a[0], nsep - a[0]) : NULL;\n                \n                if (pfx) {\n                    ne_buffer_concat(hdl->value, \" \", pfx, nsep + 1, \"='\", \n                                     a[1], \"'\", NULL);\n                }\n                else {\n                    ne_buffer_concat(hdl->value, \" \", a[0], \"='\", a[1], \"'\", NULL);\n                }\n                a += 2;\n            }\n\n            ne_buffer_czappend(hdl->value, \">\");\n        }\n\n        return ELM_flatprop;\n    }        \n\n    /* Enforce maximum number of properties per resource to prevent a\n     * memory exhaustion attack by a hostile server. */\n    if (++hdl->current->counter == MAX_PROP_COUNTER) {\n        ne_xml_set_error(hdl->parser, _(\"Response exceeds maximum property count\"));\n        return NE_XML_ABORT;\n    }\n\n    /* Add a property to this propstat */\n    n = pstat->numprops;\n\n    pstat->props = ne_realloc(pstat->props, sizeof(struct prop) * (n + 1));\n    pstat->numprops = n+1;\n\n    /* Fill in the new property. */\n    prop = &pstat->props[n];\n\n    prop->pname.name = prop->name = ne_strdup(name);\n    if (nspace[0] == '\\0') {\n\tprop->pname.nspace = prop->nspace = NULL;\n    } else {\n\tprop->pname.nspace = prop->nspace = ne_strdup(nspace);\n    }\n    prop->value = NULL;\n\n    NE_DEBUG(NE_DBG_XML, \"Got property #%d: {%s}%s.\\n\", n, \n\t     NSPACE(prop->nspace), prop->name);\n\n    /* This is under discussion at time of writing (April '01), and it\n     * looks like we need to retrieve the xml:lang property from any\n     * element here or above.\n     *\n     * Also, I think we might need attribute namespace handling here.  */\n    lang = ne_xml_get_attr(hdl->parser, atts, NULL, \"xml:lang\");\n    if (lang != NULL) {\n\tprop->lang = ne_strdup(lang);\n\tNE_DEBUG(NE_DBG_XML, \"Property language is %s\\n\", prop->lang);\n    } else {\n\tprop->lang = NULL;\n    }\n\n    hdl->depth = 0;\n\n    return ELM_flatprop;\n}\n\nstatic int endelm(void *userdata, int state,\n                  const char *nspace, const char *name)\n{\n    ne_propfind_handler *hdl = userdata;\n    struct propstat *pstat = ne_207_get_current_propstat(hdl->parser207);\n    int n;\n\n    if (hdl->depth > 0) {\n        /* nested. */\n        if (hdl->value->used < MAX_FLATPROP_LEN)\n            ne_buffer_concat(hdl->value, \"</\", nspace, name, \">\", NULL);\n        hdl->depth--;\n    } else {\n        /* end of the current property value */\n        n = pstat->numprops - 1;\n        pstat->props[n].value = ne_buffer_finish(hdl->value);\n        hdl->value = ne_buffer_create();\n    }\n    return 0;\n}\n\nstatic void end_propstat(void *userdata, void *pstat_v, \n\t\t\t const ne_status *status,\n\t\t\t const char *description)\n{\n    struct propstat *pstat = pstat_v;\n\n    /* Nothing to do if no status was given. */\n    if (!status) return;\n\n    /* If we get a non-2xx response back here, we wipe the value for\n     * each of the properties in this propstat, so the caller knows to\n     * look at the status instead. It's annoying, since for each prop\n     * we will have done an unnecessary strdup(\"\") above, but there is\n     * no easy way round that given the fact that we don't know\n     * whether we've got an error or not till after we get the\n     * property element.\n     *\n     * Interestingly IIS breaks the 2518 DTD and puts the status\n     * element first in the propstat. This is useful since then we\n     * *do* know whether each subsequent empty prop element means, but\n     * we can't rely on that here. */\n    if (status->klass != 2) {\n\tint n;\n\t\n\tfor (n = 0; n < pstat->numprops; n++) {\n\t    ne_free(pstat->props[n].value);\n\t    pstat->props[n].value = NULL;\n\t}\n    }\n\n    /* copy the status structure, and dup the reason phrase. */\n    pstat->status = *status;\n    pstat->status.reason_phrase = ne_strdup(status->reason_phrase);\n}\n\n/* Frees up a results set */\nstatic void free_propset(ne_propfind_handler *handler,\n                         ne_prop_result_set *set)\n{\n    int n;\n    \n    if (handler->destructor && set->private) {\n        handler->destructor(handler->cd_userdata, set->private);\n    }\n\n    for (n = 0; n < set->numpstats; n++) {\n\tint m;\n\tstruct propstat *p = &set->pstats[n];\n\n\tfor (m = 0; m < p->numprops; m++) {\n            if (p->props[m].nspace) ne_free(p->props[m].nspace);\n            ne_free(p->props[m].name);\n            if (p->props[m].lang) ne_free(p->props[m].lang);\n            if (p->props[m].value) ne_free(p->props[m].value);\n            p->props[m].nspace = p->props[m].lang = \n                p->props[m].value = NULL;\n\t}\n\n\tif (p->status.reason_phrase)\n\t    ne_free(p->status.reason_phrase);\n\tif (p->props)\n\t    ne_free(p->props);\n    }\n\n    if (set->pstats)\n\tne_free(set->pstats);\n    ne_uri_free(&set->uri);\n    ne_free(set);\n}\n\nstatic void end_response(void *userdata, void *resource,\n\t\t\t const ne_status *status,\n\t\t\t const char *description)\n{\n    ne_propfind_handler *handler = userdata;\n    ne_prop_result_set *set = resource;\n\n    /* Pass back the results for this resource. */\n    if (handler->callback && set->numpstats > 0)\n\thandler->callback(handler->userdata, &set->uri, set);\n\n    /* Clean up the propset tree we've just built. */\n    free_propset(handler, set);\n    handler->current = NULL;\n}\n\nne_propfind_handler *\nne_propfind_create(ne_session *sess, const char *uri, int depth)\n{\n    ne_propfind_handler *ret = ne_calloc(sizeof(ne_propfind_handler));\n    ne_uri base = {0};\n\n    ne_fill_server_uri(sess, &base);\n    base.path = ne_strdup(uri);\n\n    ret->parser = ne_xml_create();\n    ret->parser207 = ne_207_create(ret->parser, &base, ret);\n    ret->sess = sess;\n    ret->body = ne_buffer_create();\n    ret->request = ne_request_create(sess, \"PROPFIND\", uri);\n    ret->value = ne_buffer_create();\n\n    ne_add_depth_header(ret->request, depth);\n\n    ne_207_set_response_handlers(ret->parser207, \n\t\t\t\t  start_response, end_response);\n\n    ne_207_set_propstat_handlers(ret->parser207, start_propstat,\n\t\t\t\t  end_propstat);\n\n    if (ne_get_session_flag(sess, NE_SESSFLAG_SHAREPOINT))\n        ne_207_set_flags(ret->parser207, NE_207_MSSP_ESCAPING);\n\n    /* The start of the request body is fixed: */\n    ne_buffer_czappend(ret->body, \n                       \"<?xml version=\\\"1.0\\\" encoding=\\\"utf-8\\\"?>\\n\" \n                       \"<propfind xmlns=\\\"DAV:\\\">\");\n\n    ne_uri_free(&base);\n\n    return ret;\n}\n\n/* Destroy a propfind handler */\nvoid ne_propfind_destroy(ne_propfind_handler *handler)\n{\n    ne_buffer_destroy(handler->value);\n    if (handler->current)\n        free_propset(handler, handler->current);\n    ne_207_destroy(handler->parser207);\n    ne_xml_destroy(handler->parser);\n    ne_buffer_destroy(handler->body);\n    ne_request_destroy(handler->request);\n    ne_free(handler);    \n}\n\nint ne_simple_propfind(ne_session *sess, const char *href, int depth,\n\t\t\tconst ne_propname *props,\n\t\t\tne_props_result results, void *userdata)\n{\n    ne_propfind_handler *hdl;\n    int ret;\n\n    hdl = ne_propfind_create(sess, href, depth);\n    if (props != NULL) {\n\tret = ne_propfind_named(hdl, props, results, userdata);\n    } else {\n\tret = ne_propfind_allprop(hdl, results, userdata);\n    }\n\t\n    ne_propfind_destroy(hdl);\n    \n    return ret;\n}\n\nint ne_propnames(ne_session *sess, const char *href, int depth,\n\t\t  ne_props_result results, void *userdata)\n{\n    ne_propfind_handler *hdl;\n    int ret;\n\n    hdl = ne_propfind_create(sess, href, depth);\n\n    ne_buffer_czappend(hdl->body, \"<propname/></propfind>\");\n\n    ret = propfind(hdl, results, userdata);\n\n    ne_propfind_destroy(hdl);\n\n    return ret;\n}\n\nvoid ne_propfind_set_private(ne_propfind_handler *hdl,\n                             ne_props_create_complex creator,\n                             ne_props_destroy_complex destructor,\n                             void *userdata)\n{\n    hdl->creator = creator;\n    hdl->destructor = destructor;\n    hdl->cd_userdata = userdata;\n}\n"
  },
  {
    "path": "src/ne_props.h",
    "content": "/* \n   WebDAV Properties manipulation\n   Copyright (C) 1999-2021, Joe Orton <joe@manyfish.co.uk>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n   \n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n\n#ifndef NE_PROPS_H\n#define NE_PROPS_H\n\n#include \"ne_request.h\"\n#include \"ne_207.h\"\n\nNE_BEGIN_DECLS\n\n/* There are two interfaces for fetching properties. The first is\n * 'ne_simple_propfind', which is relatively simple, and easy to use,\n * but only lets you fetch FLAT properties, i.e. properties which are\n * just a string of bytes.  The complex interface is 'ne_propfind_*',\n * which is complicated, and hard to use, but lets you parse\n * structured properties, i.e.  properties which have XML content.  */\n\n/* The 'ne_simple_propfind' interface. ***\n *\n * ne_simple_propfind allows you to fetch a set of properties for a\n * single resource, or a tree of resources.  You set the operation\n * going by passing these arguments:\n *\n *  - the session which should be used.\n *  - the URI and the depth of the operation (0, 1, infinite)\n *  - the names of the properties which you want to fetch\n *  - a results callback, and the userdata for the callback.\n *\n * For each resource found, the results callback is called, passing\n * you two things along with the userdata you passed in originally:\n *\n *   - the URI of the resource (const ne_uri *uri)\n *   - the properties results set (const ne_prop_result_set *results)\n * */\n\n/* The name of a WebDAV property. 'nspace' may be NULL. */\ntypedef struct {\n    const char *nspace, *name;\n} ne_propname;\n\ntypedef struct ne_prop_result_set_s ne_prop_result_set;\n\n/* Get the value of a given property. Will return NULL if there was an\n * error fetching this property on this resource.  Call\n * ne_propset_result to get the response-status if so.  */\nconst char *ne_propset_value(const ne_prop_result_set *set,\n\t\t\t      const ne_propname *propname);\n\n/* Returns the status structure for fetching the given property on\n * this resource. This function will return NULL if the server did not\n * return the property (which is a server error). */\nconst ne_status *ne_propset_status(const ne_prop_result_set *set,\n\t\t\t\t      const ne_propname *propname);\n\n/* Returns the private pointer for the given propset. */\nvoid *ne_propset_private(const ne_prop_result_set *set);\n\n/* Return language string of property (may be NULL). */\nconst char *ne_propset_lang(const ne_prop_result_set *set,\n\t\t\t     const ne_propname *pname);\n\n/* ne_propset_iterate iterates over a properties result set,\n * calling the callback for each property in the set. userdata is\n * passed as the first argument to the callback. value may be NULL,\n * indicating an error occurred fetching this property: look at \n * status for the error in that case.\n *\n * If the iterator returns non-zero, ne_propset_iterate will return\n * immediately with that value.\n */\ntypedef int (*ne_propset_iterator)(void *userdata,\n\t\t\t\t    const ne_propname *pname,\n\t\t\t\t    const char *value,\n\t\t\t\t    const ne_status *status);\n\n/* Iterate over all the properties in 'set', calling 'iterator'\n * for each, passing 'userdata' as the first argument to callback.\n * \n * Returns:\n *   whatever value iterator returns.\n */\nint ne_propset_iterate(const ne_prop_result_set *set,\n\t\t\tne_propset_iterator iterator, void *userdata);\n\n/* Callback for handling the results of fetching properties for a\n * single resource (identified by URI 'uri').  The results are stored\n * in the result set 'results': use ne_propset_* to examine this\n * object.  */\ntypedef void (*ne_props_result)(void *userdata, const ne_uri *uri,\n                                const ne_prop_result_set *results);\n\n/* Fetch properties for a resource (if depth == NE_DEPTH_ZERO),\n * or a tree of resources (if depth == NE_DEPTH_ONE or _INFINITE).\n *\n * Names of the properties required must be given in 'props',\n * or if props is NULL, *all* properties are fetched.\n *\n * 'results' is called for each resource in the response, userdata is\n * passed as the first argument to the callback. It is important to\n * note that the callback is called as the response is read off the\n * socket, so don't do anything silly in it (e.g. sleep(100), or call\n * any functions which use this session).\n *\n * Note that if 'depth' is NE_DEPTH_INFINITY, some servers may refuse\n * the request.\n *\n * Returns NE_*.  */\nint ne_simple_propfind(ne_session *sess, const char *path, int depth,\n\t\t\tconst ne_propname *props,\n\t\t\tne_props_result results, void *userdata);\n\n/* The properties of a resource can be manipulated using ne_proppatch.\n * A single proppatch request may include any number of individual\n * \"set\" and \"remove\" operations, and is defined to have\n * \"all-or-nothing\" semantics, so either all the operations succeed,\n * or none do. */\n\n/* A proppatch operation may either set a property to have a new\n * value, in which case 'type' must be ne_propset, and 'value' must be\n * non-NULL; or it can remove a property; in which case 'type' must be\n * ne_propremove, and 'value' is ignored.  In both cases, 'name' must\n * be set to the name of the property to alter. */\nenum ne_proppatch_optype {\n    ne_propset,\n    ne_propremove\n};\ntypedef struct {\n    const ne_propname *name;\n    enum ne_proppatch_optype type;\n    const char *value;\n} ne_proppatch_operation;\n\n/* Execute a set of property operations 'ops' on 'path'. 'ops' is an\n * array terminated by an operation with a NULL 'name' field. Returns\n * NE_*. */\nint ne_proppatch(ne_session *sess, const char *path,\n\t\t const ne_proppatch_operation *ops);\n\n/* Retrieve property names for the resources at 'path'.  'results'\n * callback is called for each resource.  Use 'ne_propset_iterate' on\n * the passed results object to retrieve the list of property names.\n * */\nint ne_propnames(ne_session *sess, const char *path, int depth,\n\t\t ne_props_result results, void *userdata);\n\n/* The complex, you-do-all-the-work, property fetch interface:\n */\n\nstruct ne_propfind_handler_s;\ntypedef struct ne_propfind_handler_s ne_propfind_handler;\n\n/* Retrieve the 'private' pointer for the current propset for the\n * given handler, as returned by the ne_props_create_complex callback\n * installed using 'ne_propfind_set_private'.  If this callback was\n * not registered, this function will return NULL.  */\nvoid *ne_propfind_current_private(ne_propfind_handler *handler);\n\n/* Create a PROPFIND handler, for the given resource or set of \n * resources.\n *\n * Depth must be one of NE_DEPTH_*. */\nne_propfind_handler *\nne_propfind_create(ne_session *sess, const char *path, int depth);\n\n/* Return the XML parser for the given handler (only need if you want\n * to handle complex properties). */\nne_xml_parser *ne_propfind_get_parser(ne_propfind_handler *handler);\n\n/* This interface reserves the state integer range 'x' where 0 < x\n * and x < NE_PROPS_STATE_TOP. */\n#define NE_PROPS_STATE_TOP (NE_207_STATE_TOP + 100)\n\n/* Return the request object for the given handler.  You MUST NOT use\n * ne_set_request_body_* on this request object.  (this call is only\n * needed if for instance, you want to add extra headers to the\n * PROPFIND request).  The result of using the request pointer after\n * ne_propfind_destroy(handler) has been called is undefined. */\nne_request *ne_propfind_get_request(ne_propfind_handler *handler);\n\n/* A \"complex property\" has a value which is structured XML. To handle\n * complex properties, you must set up and register an XML handler\n * which will understand the elements which make up such properties.\n * The handler must be registered with the parser returned by\n * 'ne_propfind_get_parser'.\n *\n * To store the parsed value of the property, a 'private' structure is\n * allocated in each propset (i.e. one per resource). When parsing the\n * property value elements, for each new resource encountered in the\n * response, the 'creator' callback is called to retrieve a 'private'\n * structure for this resource.  When the private structure is no longer\n * needed, the 'destructor' callback is called to deallocate any \n * memory, if necessary.\n *\n * Whilst in XML element callbacks you will have registered to handle\n * complex properties, you can use the 'ne_propfind_current_private'\n * call to retrieve the pointer to this private structure.\n *\n * To retrieve this 'private' structure from the propset in the\n * results callback, simply call 'ne_propset_private'.\n * */\ntypedef void *(*ne_props_create_complex)(void *userdata, const ne_uri *uri);\ntypedef void (*ne_props_destroy_complex)(void *userdata, void *complex);\n\nvoid ne_propfind_set_private(ne_propfind_handler *handler,\n\t\t\t     ne_props_create_complex creator,\n\t\t\t     ne_props_destroy_complex destructor,\n\t\t\t     void *userdata);\n\n/* Fetch all properties.\n *\n * Returns NE_*. */\nint ne_propfind_allprop(ne_propfind_handler *handler, \n\t\t\tne_props_result result, void *userdata);\n\n/* Fetch all properties with names listed in array 'names', which is\n * terminated by a property with a NULL name field.  For each resource\n * encountered, the result callback will be invoked, passing in\n * 'userdata' as the first argument.\n *\n * Returns NE_*. */\nint ne_propfind_named(ne_propfind_handler *handler, \n\t\t      const ne_propname *names,\n\t\t      ne_props_result result, void *userdata);\n\n/* Destroy a propfind handler after use. */\nvoid ne_propfind_destroy(ne_propfind_handler *handler);\n\nNE_END_DECLS\n\n#endif /* NE_PROPS_H */\n"
  },
  {
    "path": "src/ne_redirect.c",
    "content": "/* \n   HTTP-redirect support\n   Copyright (C) 1999-2024, Joe Orton <joe@manyfish.co.uk>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n   \n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n\n#include \"config.h\"\n\n#ifdef HAVE_STDLIB_H\n#include <stdlib.h>\n#endif\n#ifdef HAVE_STRING_H\n#include <string.h>\n#endif\n\n#include \"ne_session.h\"\n#include \"ne_request.h\"\n#include \"ne_alloc.h\"\n#include \"ne_uri.h\"\n#include \"ne_redirect.h\"\n#include \"ne_internal.h\"\n#include \"ne_string.h\"\n\n#define REDIRECT_ID \"http://www.webdav.org/neon/hooks/http-redirect\"\n\nstruct redirect {\n    ne_uri *uri;\n};\n\n#define uri_free_clear(r_) do { if ((r_)->uri) { ne_uri_free((r_)->uri); ne_free((r_)->uri); (r_)->uri = NULL; }} while (0)\n\nstatic void create(ne_request *req, void *userdata,\n                   const char *method, const char *target)\n{\n    struct redirect *red = userdata;\n\n    uri_free_clear(red);\n}\n\nstatic int post_send(ne_request *req, void *userdata, const ne_status *status)\n{\n    struct redirect *red = userdata;\n    ne_uri *loc;\n\n    uri_free_clear(red);\n\n    if (status->klass == 3\n        && (loc = ne_get_response_location(req, NULL)) != NULL) {\n        red->uri = loc;\n        return NE_REDIRECT;\n    }\n\n    return NE_OK;\n}\n\nstatic void free_redirect(void *cookie)\n{\n    struct redirect *red = cookie;\n    uri_free_clear(red);\n    ne_free(red);\n}\n\nvoid ne_redirect_register(ne_session *sess)\n{\n    struct redirect *red = ne_calloc(sizeof *red);\n    \n    ne_hook_create_request(sess, create, red);\n    ne_hook_post_send(sess, post_send, red);\n    ne_hook_destroy_session(sess, free_redirect, red);\n\n    ne_set_session_private(sess, REDIRECT_ID, red);\n}\n\nconst ne_uri *ne_redirect_location(ne_session *sess)\n{\n    struct redirect *red = ne_get_session_private(sess, REDIRECT_ID);\n\n    return red ? red->uri : NULL;\n}\n\n"
  },
  {
    "path": "src/ne_redirect.h",
    "content": "/* \n   HTTP-redirect support\n   Copyright (C) 1999-2021, Joe Orton <joe@manyfish.co.uk>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n   \n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n\n#ifndef NE_REDIRECT_H\n#define NE_REDIRECT_H\n\n#include \"ne_request.h\"\n\nNE_BEGIN_DECLS\n\n/***\n * Since neon 0.34.0, this API is now mainly a caching wrapper around\n * ne_get_response_location(); that function should be used directly\n * if possible instead. Note that the API below does not handle\n * fragments.\n ***/\n\n/* Register redirect handling for the session: if a valid redirect\n * (30x) response is given for any request in this session, the\n * request will fail with the NE_REDIRECT code, and the destination of\n * the redirect can be retrieved using ne_redirect_location(). */\nvoid ne_redirect_register(ne_session *sess);\n\n/* Returns location of last redirect for the session.  Returns NULL if\n * no redirect has been encountered for given session, or the last\n * redirect encountered could not be parsed. */\nconst ne_uri *ne_redirect_location(ne_session *sess);\n\nNE_END_DECLS\n\n#endif /* NE_REDIRECT_H */\n"
  },
  {
    "path": "src/ne_request.c",
    "content": "/* \n   HTTP request/response handling\n   Copyright (C) 1999-2026, Joe Orton <joe@manyfish.co.uk>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n   \n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n\n/* This is the HTTP client request/response implementation.\n * The goal of this code is to be modular and simple.\n */\n\n#include \"config.h\"\n\n#include <sys/types.h>\n\n#include <errno.h>\n#include <fcntl.h>\n#ifdef HAVE_STRING_H\n#include <string.h>\n#endif\n#ifdef HAVE_STRINGS_H\n#include <strings.h>\n#endif \n#ifdef HAVE_STDLIB_H\n#include <stdlib.h>\n#endif\n#ifdef HAVE_UNISTD_H\n#include <unistd.h>\n#endif\n#include <time.h>\n\n#include \"ne_internal.h\"\n\n#include \"ne_alloc.h\"\n#include \"ne_request.h\"\n#include \"ne_string.h\" /* for ne_buffer */\n#include \"ne_utils.h\"\n#include \"ne_socket.h\"\n#include \"ne_uri.h\"\n#include \"ne_dates.h\"\n\n#include \"ne_private.h\"\n\n#define EOL \"\\r\\n\"\n\nstruct body_reader {\n    ne_block_reader handler;\n    ne_accept_response accept_response;\n    unsigned int use;\n    void *userdata;\n    struct body_reader *next;\n};\n\nstruct interim_handler {\n    ne_interim_response_fn fn;\n    void *userdata;\n    struct interim_handler *next;\n};\n\nstruct field {\n    char *name, *value;\n    size_t vlen;\n    struct field *next;\n};\n\n/* Maximum number of header fields per response: */\n#define MAX_HEADER_FIELDS (100)\n/* Size of hash table; 43 is the smallest prime for which the common\n * header names hash uniquely using the *33 hash function. */\n#define HH_HASHSIZE (43)\n\n/* Array type for storing a hash of the header fields. */\ntypedef struct field *field_hash[HH_HASHSIZE];\n\n/* Hash iteration step: *33 known to be a good hash for ASCII, see RSE. */\n#define HH_ITERATE(hash, ch) (((hash)*33 + (unsigned char)(ch)) % HH_HASHSIZE)\n\n/* pre-calculated hash values for given header names: */\n#define HH_HV_CONNECTION        (0x14)\n#define HH_HV_PROXY_CONNECTION  (0x1A)\n#define HH_HV_CONTENT_LENGTH    (0x13)\n#define HH_HV_TRANSFER_ENCODING (0x07)\n#define HH_HV_LOCATION          (0x05)\n#define HH_HV_RETRY_AFTER       (0x28)\n\nstruct ne_request_s {\n    /* Buffer for reading the response message lines or body. */\n    char respbuf[NE_BUFSIZ];\n\n    char *method, *target; /* method and request-target */\n    ne_buffer *headers; /* request headers */\n\n    /* Request body provider callback, must be non-NULL if body_length\n     * is non-zero. */\n    ne_provide_body body_cb;\n    void *body_ud;\n\n    /* Request body source: file or buffer (if not callback). */\n    union {\n        struct {\n            int fd;\n            ne_off_t offset, length;\n            ne_off_t remain; /* remaining bytes to send. */\n        } file;\n\tstruct {\n            /* length bytes @ buffer = whole body.\n             * remain bytes @ pnt = remaining bytes to send */\n\t    const char *buffer, *pnt;\n\t    size_t length, remain;\n\t} buf;\n    } body;\n    /* Length of request body, -1 means chunked */\n    ne_off_t body_length;\n\n    /* Response transfer encoding types */\n    struct ne_response {\n\tenum {\n\t    R_TILLEOF = 0, /* read till eof */\n\t    R_NO_BODY, /* implicitly no body (HEAD, 204, 304) */\n\t    R_CHUNKED, /* using chunked transfer-encoding */\n\t    R_CLENGTH  /* using given content-length */\n\t} mode;\n        union {\n            /* clen: used if mode == R_CLENGTH; total and bytes\n             * remaining to be read of response body. */\n            struct {\n                ne_off_t total, remain;\n            } clen;\n            /* chunk: used if mode == R_CHUNKED; total and bytes\n             * remaining to be read of current chunk */\n            struct {\n                size_t total, remain;\n            } chunk;\n        } body;\n        ne_off_t progress; /* number of bytes read of response */\n    } resp;\n    \n    /* Response header fields; response_trailers is allocated only if\n     * (rarely) required. */\n    field_hash *response_trailers, response_headers;\n\n    /* Iterators for the response_headers and trailers. */\n    unsigned int headers_index, trailers_index;\n\n    /* Callbacks and hooks. */\n    struct body_reader *body_readers;\n    struct interim_handler *interim_handler;\n    struct hook *private;\n\n    /*** Miscellaneous ***/\n    ne_uri *target_uri;\n    unsigned int method_is_head;\n    unsigned int can_persist;\n\n    int flags[NE_REQFLAG_LAST];\n\n    ne_session *session;\n    ne_status status;\n};\n\nstatic int open_connection(ne_session *sess);\nstatic int read_header_fields(ne_request *req, field_hash **fields);\n\n/* Returns hash value for header 'name', converting it to lower-case\n * in-place. */\nstatic inline unsigned int hash_and_lower(char *name)\n{\n    char *pnt;\n    unsigned int hash = 0;\n\n    for (pnt = name; *pnt != '\\0'; pnt++) {\n\t*pnt = ne_tolower(*pnt);\n\thash = HH_ITERATE(hash,*pnt);\n    }\n\n    return hash;\n}\n\n/* Abort a request due to an non-recoverable HTTP protocol error,\n * whilst doing 'doing'.  'code', if non-zero, is the socket error\n * code, NE_SOCK_*, or if zero, is ignored. */\nstatic int aborted(ne_request *req, const char *doing, ssize_t code)\n{\n    ne_session *sess = req->session;\n    int ret = NE_ERROR;\n\n    NE_DEBUG(NE_DBG_HTTP, \"Aborted request (%\" NE_FMT_SSIZE_T \"): %s\\n\",\n\t     code, doing);\n\n    switch(code) {\n    case NE_SOCK_CLOSED:\n\tif (sess->nexthop->proxy != PROXY_NONE) {\n\t    ne_set_error(sess, _(\"%s: connection was closed by proxy server\"),\n\t\t\t doing);\n\t} else {\n\t    ne_set_error(sess, _(\"%s: connection was closed by server\"),\n\t\t\t doing);\n\t}\n\tbreak;\n    case NE_SOCK_TIMEOUT:\n\tne_set_error(sess, _(\"%s: connection timed out\"), doing);\n\tret = NE_TIMEOUT;\n\tbreak;\n    case NE_SOCK_ERROR:\n    case NE_SOCK_RESET:\n    case NE_SOCK_TRUNC:\n        ne_set_error(sess, \"%s: %s\", doing, ne_sock_error(sess->socket));\n        break;\n    case 0:\n\tne_set_error(sess, \"%s\", doing);\n\tbreak;\n    }\n\n    ne_close_connection(sess);\n    return ret;\n}\n\nstatic void notify_status(ne_session *sess, ne_session_status status)\n{\n    if (sess->notify_cb) {\n\tsess->notify_cb(sess->notify_ud, status, &sess->status);\n    }\n}\n\nstatic void *get_private(const struct hook *hk, const char *id)\n{\n    for (; hk != NULL; hk = hk->next)\n\tif (strcmp(hk->id, id) == 0)\n\t    return hk->userdata;\n    return NULL;\n}\n\nvoid *ne_get_request_private(ne_request *req, const char *id)\n{\n    return get_private(req->private, id);\n}\n\nvoid *ne_get_session_private(ne_session *sess, const char *id)\n{\n    return get_private(sess->private, id);\n}\n\nvoid ne_set_request_private(ne_request *req, const char *id, void *userdata)\n{\n    struct hook *hk = ne_malloc(sizeof (struct hook)), *pos;\n\n    if (req->private != NULL) {\n\tfor (pos = req->private; pos->next != NULL; pos = pos->next)\n\t    /* nullop */;\n\tpos->next = hk;\n    } else {\n\treq->private = hk;\n    }\n\n    hk->id = id;\n    hk->fn = NULL;\n    hk->userdata = userdata;\n    hk->next = NULL;\n}\n\nstatic ssize_t body_string_send(void *userdata, char *buffer, size_t count)\n{\n    ne_request *req = userdata;\n    \n    if (count == 0) {\n\treq->body.buf.remain = req->body.buf.length;\n\treq->body.buf.pnt = req->body.buf.buffer;\n    } else {\n\t/* if body_left == 0 we fall through and return 0. */\n\tif (req->body.buf.remain < count)\n\t    count = req->body.buf.remain;\n\n\tmemcpy(buffer, req->body.buf.pnt, count);\n\treq->body.buf.pnt += count;\n\treq->body.buf.remain -= count;\n    }\n\n    return count;\n}    \n\nstatic ssize_t body_fd_send(void *userdata, char *buffer, size_t count)\n{\n    ne_request *req = userdata;\n\n    if (count) {\n        ssize_t ret;\n\n        if (req->body.file.remain == 0)\n            return 0;\n\n        /* Casts here are necessary for LFS platforms for safe and\n         * warning-free assignment/comparison between 32-bit size_t\n         * and 64-bit off64_t: */\n        if ((ne_off_t)count > req->body.file.remain)\n            count = (size_t)req->body.file.remain;\n        \n        ret = read(req->body.file.fd, buffer, count);\n        if (ret > 0) {\n            req->body.file.remain -= ret;\n            return ret;\n        }\n        else if (ret == 0) {\n            ne_set_error(req->session, \n                         _(\"Premature EOF in request body file\"));\n        }\n        else if (ret < 0) {\n            char err[200];\n            int errnum = errno;\n\n            ne_set_error(req->session, \n                         _(\"Failed reading request body file: %s\"),\n                         ne_strerror(errnum, err, sizeof err));\n        }\n\n        return -1;\n    } else {\n        ne_off_t newoff;\n\n        /* rewind for next send. */\n        newoff = ne_lseek(req->body.file.fd, req->body.file.offset, SEEK_SET);\n        if (newoff == req->body.file.offset) {\n            req->body.file.remain = req->body.file.length;\n            return 0;\n        } else {\n            char err[200], offstr[20];\n\n            if (newoff == -1) {\n                /* errno was set */\n                ne_strerror(errno, err, sizeof err);\n            } else {\n                ne_strnzcpy(err, _(\"offset invalid\"), sizeof err);\n            }\n            ne_snprintf(offstr, sizeof offstr, \"%\" FMT_NE_OFF_T,\n                        req->body.file.offset);\n            ne_set_error(req->session, \n                         _(\"Could not seek to offset %s\"\n                           \" of request body file: %s\"), \n                           offstr, err);\n            return -1;\n        }\n    }\n}\n\n/* For accurate persistent connection handling, for any write() or\n * read() operation for a new request on an already-open connection,\n * an EOF or RST error MUST be treated as a persistent connection\n * timeout, and the request retried on a new connection.  Once a\n * read() operation has succeeded, any subsequent error MUST be\n * treated as fatal.  A 'retry' flag is used; retry=1 represents the\n * first case, retry=0 the latter. */\n\n/* RETRY_RET() crafts a function return value given the 'retry' flag,\n * the socket error 'code', and the return value 'acode' from the\n * aborted() function. */\n#define RETRY_RET(retry, code, acode) \\\n((((code) == NE_SOCK_CLOSED || (code) == NE_SOCK_RESET || \\\n (code) == NE_SOCK_TRUNC) && retry) ? NE_RETRY : (acode))\n\n/* For sending chunks, an 8-byte prefix is reserved at the beginning\n * of the buffer.  This is large enough for a trailing \\r\\n for the\n * previous chunk, the chunk size, and the \\r\\n following the\n * chunk-size. */\n#define CHUNK_OFFSET (8)\n#define CHUNK_TERM \"\\r\\n0\\r\\n\\r\\n\"\n#define CHUNK_NULL_TERM \"0\\r\\n\\r\\n\"\n\n/* Sends the request body; returns 0 on success or an NE_* error code.\n * If retry is non-zero; will return NE_RETRY on persistent connection\n * timeout.  On error, the session error string is set and the\n * connection is closed. */\nstatic int send_request_body(ne_request *req, int retry)\n{\n    ne_session *const sess = req->session;\n    char buffer[NE_BUFSIZ], *start;\n    ssize_t bytes;\n    size_t buflen;\n    int chunked = req->body_length < 0, chunknum = 0;\n    int ret;\n\n    NE_DEBUG(NE_DBG_HTTP, \"Sending request body:\\n\");\n\n    /* Set up status union and (start, buflen) as the buffer to be\n     * passed the supplied callback. */\n    if (chunked) {\n        start = buffer + CHUNK_OFFSET;\n        buflen = sizeof(buffer) - CHUNK_OFFSET;\n        req->session->status.sr.total = -1;\n    }\n    else {\n        start = buffer;\n        buflen = sizeof buffer;\n        req->session->status.sr.total = req->body_length;\n    }\n\n    req->session->status.sr.progress = 0;\n    notify_status(sess, ne_status_sending);\n    \n    /* tell the source to start again from the beginning. */\n    if (req->body_cb(req->body_ud, NULL, 0) != 0) {\n        ne_close_connection(sess);\n        return NE_ERROR;\n    }\n    \n    while ((bytes = req->body_cb(req->body_ud, start, buflen)) > 0) {\n        req->session->status.sr.progress += bytes;\n        if (chunked) {\n            /* Overwrite the buffer prefix with the appropriate chunk\n             * size; since ne_snprintf always NUL-terminates, the \\n\n             * is omitted and placed over the NUL afterwards. */\n            if (chunknum++ == 0)\n                ne_snprintf(buffer, CHUNK_OFFSET, \n                            \"%06x\\r\", (unsigned)bytes);\n            else\n                ne_snprintf(buffer, CHUNK_OFFSET, \n                            \"\\r\\n%04x\\r\", (unsigned)bytes);\n            buffer[CHUNK_OFFSET - 1] = '\\n';\n            bytes += CHUNK_OFFSET;\n        }\n        ret = ne_sock_fullwrite(sess->socket, buffer, bytes);\n\n        if (ret < 0) {\n            int aret = aborted(req, _(\"Could not send request body\"), ret);\n            return RETRY_RET(retry, ret, aret);\n        }\n\n\tNE_DEBUG(NE_DBG_HTTPBODY, \n\t\t \"Body block (%\" NE_FMT_SSIZE_T \" bytes):\\n[%.*s]\\n\",\n\t\t bytes, (int)bytes, buffer);\n\n        /* invoke progress callback */\n        notify_status(sess, ne_status_sending);\n    }\n\n    if (bytes) {\n        NE_DEBUG(NE_DBG_HTTP, \"Request body provider failed with \"\n                 \"%\" NE_FMT_SSIZE_T \"\\n\", bytes);\n        ne_close_connection(sess);\n        return NE_ERROR;\n    }\n\n    if (chunked) {\n        if (chunknum == 0)\n            ret = ne_sock_fullwrite(sess->socket, CHUNK_NULL_TERM, \n                                    sizeof(CHUNK_NULL_TERM) - 1);\n        else\n            ret = ne_sock_fullwrite(sess->socket, CHUNK_TERM, \n                                    sizeof(CHUNK_TERM) - 1);\n        if (ret < 0) {\n            int aret = aborted(req, _(\"Could not send chunked \"\n                                      \"request terminator\"), ret);\n            return RETRY_RET(retry, ret, aret);\n        }\n    }\n    \n    return NE_OK;\n}\n\n/* Set up buffer for initial request headers. */\nstatic ne_buffer *initial_request_headers(ne_request *req) \n{\n    ne_session *const sess = req->session;\n    ne_buffer *hdrs = ne_buffer_create();\n\n    if (sess->user_agent) {\n        ne_buffer_zappend(hdrs, sess->user_agent);\n    }\n\n    /* If persistent connections are disabled, just send Connection:\n     * close; otherwise, send Connection: Keep-Alive to pre-1.1 origin\n     * servers to try harder to get a persistent connection, except if\n     * using a proxy as per 2068§19.7.1.  Always add TE: trailers. */\n    if (!sess->flags[NE_SESSFLAG_PERSIST]) {\n       ne_buffer_czappend(hdrs, \"Connection: TE, close\" EOL);\n    } \n    else if (!sess->is_http11 && !sess->any_proxy_http) {\n        ne_buffer_czappend(hdrs, \n                           \"Keep-Alive: \" EOL\n                          \"Connection: TE, Keep-Alive\" EOL);\n    } \n    else if (!req->session->is_http11 && !sess->any_proxy_http) {\n        ne_buffer_czappend(hdrs, \n                           \"Keep-Alive: \" EOL\n                           \"Proxy-Connection: Keep-Alive\" EOL\n                           \"Connection: TE\" EOL);\n    } \n    else {\n        ne_buffer_czappend(hdrs, \"Connection: TE\" EOL);\n    }\n\n    ne_buffer_concat(hdrs, \"TE: trailers\" EOL \"Host: \", \n                     req->session->server.hostport, EOL, NULL);\n\n    return hdrs;\n}\n\nint ne_accept_always(void *userdata, ne_request *req, const ne_status *st)\n{\n    return 1;\n}\t\t\t\t   \n\nint ne_accept_2xx(void *userdata, ne_request *req, const ne_status *st)\n{\n    return (st->klass == 2);\n}\n\nne_request *ne_request_create(ne_session *sess, const char *method,\n                              const char *target)\n{\n    ne_request *req = ne_calloc(sizeof *req);\n\n    req->session = sess;\n    \n    /* Presume the method is idempotent by default. */\n    req->flags[NE_REQFLAG_IDEMPOTENT] = 1;\n    /* Expect-100 default follows the corresponding session flag. */\n    req->flags[NE_REQFLAG_EXPECT100] = sess->flags[NE_SESSFLAG_EXPECT100];\n    /* 1xx timeouts default to on. */\n    req->flags[NE_REQFLAG_1XXTIMEOUT] = 1;\n\n    /* Add in the fixed headers */\n    req->headers = initial_request_headers(req);\n\n    /* Set the standard stuff */\n    req->method = ne_strdup(method);\n    req->method_is_head = (strcmp(method, \"HEAD\") == 0);\n\n    /* Only use an absoluteURI here when we might be using an HTTP\n     * proxy, and SSL is in use: some servers can't parse them. */\n    if (sess->any_proxy_http && !req->session->use_ssl && target[0] == '/')\n        req->target = ne_concat(req->session->scheme, \"://\",\n                                req->session->server.hostport,\n                                target, NULL);\n    else\n        req->target = ne_strdup(target);\n\n    {\n\tstruct hook *hk;\n\n\tfor (hk = sess->create_req_hooks; hk != NULL; hk = hk->next) {\n\t    ne_create_request_fn fn = (ne_create_request_fn)hk->fn;\n\t    fn(req, hk->userdata, req->method, req->target);\n\t}\n    }\n\n    return req;\n}\n\n/* Reconstruct the request target URI following RFC 9112§3.3. Returns\n * zero on success or non-zero on error. */\nstatic int get_request_target_uri(ne_request *req, ne_uri *uri)\n{\n    if (strcmp(req->target, \"*\") == 0\n        || strcmp(req->method, \"CONNECT\") == 0) {\n        /* asterisk-form or authority-form. Since neon only ever uses\n         * authority-form with a CONNECT to the origin server (which\n         * is the session host) there is no need to re-parse\n         * req->target to extract it. */\n        ne_fill_server_uri(req->session, uri);\n        uri->path = ne_strdup(\"\");\n        return 0;\n    }\n    else if (req->target[0] == '/') {\n        /* origin-form. */\n        ne_fill_server_uri(req->session, uri);\n        uri->path = ne_strdup(req->target);\n        return 0;\n    }\n    else {\n        /* absolute-form */\n        return ne_uri_parse(req->target, uri);\n    }\n}\n\nconst ne_uri *ne_get_request_target(ne_request *req)\n{\n    if (req->target_uri == NULL) {\n        ne_uri *uri = ne_calloc(sizeof *uri);\n\n        if (get_request_target_uri(req, uri) == 0) {\n            req->target_uri = uri;\n        }\n        else {\n            ne_uri_free(uri);\n            ne_free(uri);\n        }\n    }\n\n    return req->target_uri;\n}\n\n/* Set the request body length to 'length' */\nstatic void set_body_length(ne_request *req, ne_off_t length)\n{\n    req->body_length = length;\n\n    if (length >= 0)\n        ne_print_request_header(req, \"Content-Length\", \"%\" FMT_NE_OFF_T, length);\n    else /* length < 0 => chunked body */\n        ne_add_request_header(req, \"Transfer-Encoding\", \"chunked\");\n\n}\n\nvoid ne_set_request_body_buffer(ne_request *req, const char *buffer,\n\t\t\t\tsize_t size)\n{\n    req->body.buf.buffer = buffer;\n    req->body.buf.length = size;\n    req->body_cb = body_string_send;\n    req->body_ud = req;\n    set_body_length(req, size);\n}\n\nvoid ne_set_request_body_provider(ne_request *req, ne_off_t bodysize,\n\t\t\t\t  ne_provide_body provider, void *ud)\n{\n    req->body_cb = provider;\n    req->body_ud = ud;\n    set_body_length(req, bodysize);\n}\n\nvoid ne_set_request_body_fd(ne_request *req, int fd,\n                            ne_off_t offset, ne_off_t length)\n{\n    req->body.file.fd = fd;\n    req->body.file.offset = offset;\n    req->body.file.length = length;\n    req->body_cb = body_fd_send;\n    req->body_ud = req;\n    set_body_length(req, length);\n}\n\nvoid ne_set_request_flag(ne_request *req, ne_request_flag flag, int value)\n{\n    if (flag < (ne_request_flag)NE_REQFLAG_LAST) {\n        req->flags[flag] = value;\n    }\n}\n\nint ne_get_request_flag(ne_request *req, ne_request_flag flag)\n{\n    if (flag < (ne_request_flag)NE_REQFLAG_LAST) {\n        return req->flags[flag];\n    }\n    return -1;\n}\n\nvoid ne_add_request_header(ne_request *req, const char *name, \n\t\t\t   const char *value)\n{\n    ne_buffer_concat(req->headers, name, \": \", value, EOL, NULL);\n}\n\nvoid ne_print_request_header(ne_request *req, const char *name,\n\t\t\t     const char *format, ...)\n{\n    va_list params;\n    char buf[NE_BUFSIZ];\n    \n    va_start(params, format);\n    ne_vsnprintf(buf, sizeof buf, format, params);\n    va_end(params);\n    \n    ne_buffer_concat(req->headers, name, \": \", buf, EOL, NULL);\n}\n\n/* Returns the value of the response header 'name', for which the hash\n * value is 'h', or NULL if the header is not found. */\nstatic char *get_field_hv(field_hash *fh, unsigned int h, const char *name)\n{\n    struct field *f;\n\n    for (f = (*fh)[h]; f; f = f->next)\n        if (strcmp(f->name, name) == 0)\n            return f->value;\n\n    return NULL;\n}\n\nstatic char *get_response_header_hv(ne_request *req, unsigned int h,\n                                    const char *name)\n{\n    return get_field_hv(&req->response_headers, h, name);\n}\n\nstatic const char *get_header_field(field_hash *hv, const char *name)\n{\n    char *lcname = ne_strdup(name);\n    unsigned int hash = hash_and_lower(lcname);\n    char *value = get_field_hv(hv, hash, lcname);\n    ne_free(lcname);\n    return value;\n}\n\nconst char *ne_get_response_header(ne_request *req, const char *name)\n{\n    return get_header_field(&req->response_headers, name);\n}\n\nconst char *ne_get_response_trailer(ne_request *req, const char *name)\n{\n    if (req->response_trailers)\n        return get_header_field(req->response_trailers, name);\n    else\n        return NULL;\n}\n\nstatic void *header_iterate(struct field *f,\n                            field_hash *hash, unsigned int *index,\n                            const char **name, const char **value)\n{\n    unsigned int n;\n\n    /* Short circuit when there is no trailers array. */\n    if (f == NULL && hash == NULL) return NULL;\n\n    if (f == NULL) {\n        n = 0;\n    }\n    else if ((f = f->next) == NULL) {\n        n = *index + 1;\n    }\n\n    if (f == NULL) {\n        while (n < HH_HASHSIZE && (*hash)[n] == NULL)\n            n++;\n        if (n == HH_HASHSIZE)\n            return NULL; /* no more headers */\n        f = (*hash)[n];\n        *index = n;\n    }\n    \n    *name = f->name;\n    *value = f->value;\n    return f;\n}\n\nvoid *ne_response_header_iterate(ne_request *req, void *cursor,\n                                 const char **name, const char **value)\n{\n    return header_iterate(cursor, &req->response_headers, &req->headers_index,\n                          name, value);\n}\n\nvoid *ne_response_trailer_iterate(ne_request *req, void *cursor,\n                                  const char **name, const char **value)\n{\n    return header_iterate(cursor, req->response_trailers, &req->trailers_index,\n                          name, value);\n}\n\n/* Removes the response header 'name', which has hash value 'hash'. */\nstatic void remove_response_header(ne_request *req, const char *name, \n                                   unsigned int hash)\n{\n    struct field **ptr = req->response_headers + hash;\n\n    while (*ptr) {\n        struct field *const f = *ptr;\n\n        if (strcmp(f->name, name) == 0) {\n            *ptr = f->next;\n            ne_free(f->name);\n            ne_free(f->value);\n            ne_free(f);\n            return;\n        }\n        \n        ptr = &f->next;\n    }\n}\n\n/* Free all stored response headers. */\nstatic void free_fields(field_hash *fields)\n{\n    int n;\n\n    for (n = 0; n < HH_HASHSIZE; n++) {\n        struct field **ptr = &(*fields)[n];\n\n        while (*ptr) {\n            struct field *const f = *ptr;\n            *ptr = f->next;\n            ne_free(f->name);\n            ne_free(f->value);\n            ne_free(f);\n\t}\n    }\n}\n\nstatic void free_response_headers(ne_request *req)\n{\n    free_fields(&req->response_headers);\n    if (req->response_trailers) free_fields(req->response_trailers);\n}\n\n/* Read response headers. */\nstatic int read_response_headers(ne_request *req)\n{\n    field_hash *fh = &req->response_headers;\n\n    /* Clear any response headers from previous invocations\n     * (e.g. retried requests, interim responses. */\n    free_response_headers(req);\n\n    return read_header_fields(req, &fh);\n}\n\nne_uri *ne_get_response_location(ne_request *req, const char *fragment)\n{\n    const char *location;\n    ne_uri dest, *ret = NULL;\n    const ne_uri *base;\n\n    location = get_response_header_hv(req, HH_HV_LOCATION, \"location\");\n    if (location == NULL)\n\treturn NULL;\n\n    memset(&dest, 0, sizeof dest);\n\n    /* Location is a URI-reference (RFC9110§10.2.2) relative to the\n     * request target URI; determine each of these then resolve. */\n\n    /* Parse the Location header */\n    if (ne_uri_parse(location, &dest) || !dest.path) {\n        ne_set_error(req->session, _(\"Could not parse redirect \"\n                                     \"destination URL\"));\n        goto fail;\n    }\n\n    if ((base = ne_get_request_target(req)) == NULL) {\n        ne_set_error(req->session, _(\"Could not parse request \"\n                                     \"target URI\"));\n        goto fail;\n    }\n\n    ret = ne_malloc(sizeof *ret);\n    ne_uri_resolve(base, &dest, ret);\n\n    /* HTTP-specific fragment handling is a MUST in RFC9110§10.2.2: */\n    if (fragment && !dest.fragment) {\n        ret->fragment = ne_strdup(fragment);\n    }\n\nfail:\n    ne_uri_free(&dest);\n\n    return ret;\n}\n\ntime_t ne_get_response_retry_after(ne_request *req)\n{\n    char *val, *endp;\n    unsigned long abs;\n    time_t ret;\n\n    val = get_response_header_hv(req, HH_HV_RETRY_AFTER, \"retry-after\");\n    if (!val) return 0;\n\n    errno = 0;\n    abs = strtoul(val, &endp, 10);\n    if (errno == 0 && abs != ULONG_MAX && *endp == '\\0') {\n        ret = time(NULL) + abs;\n    }\n    else {\n        if ((ret = ne_httpdate_parse(val)) == -1)\n            ret = 0;\n    }\n\n    return ret;\n}\n\nvoid ne_add_response_body_reader(ne_request *req, ne_accept_response acpt,\n\t\t\t\t ne_block_reader rdr, void *userdata)\n{\n    struct body_reader *new = ne_malloc(sizeof *new);\n    new->accept_response = acpt;\n    new->handler = rdr;\n    new->userdata = userdata;\n    new->next = req->body_readers;\n    req->body_readers = new;\n}\n\nvoid ne_add_interim_handler(ne_request *req, ne_interim_response_fn fn,\n                            void *userdata)\n{\n    struct interim_handler *new = ne_malloc(sizeof *new);\n\n    new->fn = fn;\n    new->userdata = userdata;\n    new->next = req->interim_handler;\n    req->interim_handler = new;\n}\n\nvoid ne_request_destroy(ne_request *req) \n{\n    struct body_reader *rdr, *next_rdr;\n    struct interim_handler *ih, *next_ih;\n    struct hook *hk, *next_hk;\n\n    NE_DEBUG(NE_DBG_HTTP, \"req: Destroy (%s %s).\\n\", req->method, req->target);\n\n    ne_free(req->target);\n    ne_free(req->method);\n    if (req->target_uri) {\n        ne_uri_free(req->target_uri);\n        ne_free(req->target_uri);\n    }\n\n    for (rdr = req->body_readers; rdr != NULL; rdr = next_rdr) {\n\tnext_rdr = rdr->next;\n\tne_free(rdr);\n    }\n\n    for (ih = req->interim_handler; ih; ih = next_ih) {\n        next_ih = ih->next;\n        ne_free(ih);\n    }\n\n    free_response_headers(req);\n    if (req->response_trailers) ne_free(req->response_trailers);\n\n    ne_buffer_destroy(req->headers);\n\n    NE_DEBUG(NE_DBG_HTTP, \"Running destroy hooks.\\n\");\n    for (hk = req->session->destroy_req_hooks; hk; hk = next_hk) {\n\tne_destroy_req_fn fn = (ne_destroy_req_fn)hk->fn;\n        next_hk = hk->next;\n\tfn(req, hk->userdata);\n    }\n\n    for (hk = req->private; hk; hk = next_hk) {\n\tnext_hk = hk->next;\n\tne_free(hk);\n    }\n\n    if (req->status.reason_phrase)\n\tne_free(req->status.reason_phrase);\n\n    ne_free(req);\n}\n\n/* Read an HTTP message line following RFC 9112§2.2, returning <0 on\n * error, >= 0 for line length excluding trailing CRLF. Bare CR and\n * NUL bytes are converted to spaces. */\nstatic ssize_t read_message_line(ne_socket *sock, char *const buf, size_t buflen)\n{\n    ssize_t len = ne_sock_readline(sock, buf, buflen);\n\n    if (len <= 0) {\n        return len;\n    }\n\n    NE_DEBUG(NE_DBG_HTTP, \"req: Line: %.*s\\n\", (int)len-1, buf);\n\n    if (len == 1) {\n        /* bare LF => empty line. */\n        return 0;\n    }\n    else /* len > 1 */ {\n        char *p = buf + len - 1;\n\n        *p-- = '\\0';\n        len -= 1;\n\n        /* NUL terminate at the CR */\n        if (*p == '\\r') {\n            *p-- = '\\0';\n            len -= 1;\n        }\n\n        /* Replace any bare CR or NUL characters. */\n        while (p >= buf) {\n            if (*p == '\\r' || *p == '\\0') *p = ' ';\n            p--;\n        }\n    }\n\n    return len;\n}\n\n/* Reads a block of the response into BUFFER, which is of size\n * *BUFLEN.  Returns zero on success or non-zero on error.  On\n * success, *BUFLEN is updated to be the number of bytes read into\n * BUFFER (which will be 0 to indicate the end of the response).  On\n * error, the connection is closed and the session error string is\n * set.  */\nstatic int read_response_block(ne_request *req, struct ne_response *resp, \n\t\t\t       char *buffer, size_t *buflen) \n{\n    ne_socket *const sock = req->session->socket;\n    ssize_t readlen;\n    \n    switch (resp->mode) {\n    case R_CHUNKED:\n        /* Chunked transfer-encoding: chunk syntax is \"SIZE CRLF CHUNK\n         * CRLF SIZE CRLF CHUNK CRLF ...\" followed by zero-length\n         * chunk: \"CHUNK CRLF 0 CRLF\".  resp.chunk.remain contains the\n         * number of bytes left to read in the current chunk. */\n\tif (resp->body.chunk.remain == 0) {\n            unsigned long chunk_len;\n            const char *cptr;\n            char *ptr;\n\n            /* Read chunk-size. */\n            readlen = ne_sock_readline(sock, req->respbuf, sizeof req->respbuf);\n            if (readlen < 0)\n                return aborted(req, _(\"Could not read chunk size\"), readlen);\n            /* Minimum valid line is 0<CR><LF> */\n            if (readlen < 3 || req->respbuf[(size_t)readlen - 2] != '\\r')\n                return aborted(req, _(\"Invalid chunk-size line\"), 0);\n\n            /* chunk-size is followed by chunk-ext => *(BWS \";\" ...)\n             * NUL-terminate here to make the sanity-check easier.*/\n            ptr = strchr(req->respbuf, ';');\n            if (ptr) {\n                /* Iterate backwards through any BWS, if present. */\n                while (ptr > req->respbuf\n                       && (ptr[-1] == ' ' || ptr[-1] == '\\t'))\n                    ptr--;\n                *ptr = '\\0';\n            }\n\n            /* Limit chunk size to <= UINT_MAX, for sanity; must have\n             * a following NUL due to chunk-ext handling above. */\n            chunk_len = ne_strhextoul(req->respbuf, &cptr);\n            if (errno || (*cptr != '\\0' && *cptr != '\\r')\n                || chunk_len > UINT_MAX) {\n                return aborted(req, _(\"Could not parse chunk size\"), 0);\n            }\n            NE_DEBUG(NE_DBG_HTTP, \"req: Chunk size: %lu\\n\", chunk_len);\n            resp->body.chunk.remain = chunk_len;\n\t}\n        if (resp->body.chunk.remain < *buflen)\n            *buflen = resp->body.chunk.remain;\n\tbreak;\n    case R_CLENGTH:\n        if (resp->body.clen.remain < (off_t)*buflen)\n            *buflen = (size_t)resp->body.clen.remain;\n\tbreak;\n    case R_TILLEOF:\n\t/* fill whatever buffer space. */\n\tbreak;\n    case R_NO_BODY:\n    default:\n\t*buflen = 0;\n\tbreak;\n    }\n\n    NE_DEBUG(NE_DBG_HTTP, \"req: Reading %\" NE_FMT_SIZE_T \" bytes \"\n             \"of response body.\\n\", *buflen);\n    /* Special case when reaching the end of a known-length response,\n     * *buflen is set to zero and nothing further is read from the\n     * socket. */\n    if (*buflen == 0) {\n\treturn 0;\n    }\n    readlen = ne_sock_read(sock, buffer, *buflen);\n\n    /* EOF is only valid when response body is delimited by it.\n     * Strictly, an SSL truncation should not be treated as an EOF in\n     * any case, but SSL servers are just too buggy.  */\n    if (resp->mode == R_TILLEOF && \n\t(readlen == NE_SOCK_CLOSED || readlen == NE_SOCK_TRUNC)) {\n\tNE_DEBUG(NE_DBG_HTTP, \"Got EOF.\\n\");\n\treq->can_persist = 0;\n\treadlen = 0;\n    } else if (readlen < 0) {\n\treturn aborted(req, _(\"Could not read response body\"), readlen);\n    } else {\n\tNE_DEBUG(NE_DBG_HTTP, \"Got %\" NE_FMT_SSIZE_T \" bytes.\\n\", readlen);\n    }\n    /* safe to cast: readlen guaranteed to be >= 0 above */\n    *buflen = (size_t)readlen;\n    NE_DEBUG(NE_DBG_HTTPBODY,\n\t     \"Read block (%\" NE_FMT_SSIZE_T \" bytes):\\n[%.*s]\\n\",\n\t     readlen, (int)readlen, buffer);\n    if (resp->mode == R_CHUNKED) {\n\tresp->body.chunk.remain -= readlen;\n\tif (resp->body.chunk.remain == 0) {\n\t    char crlfbuf[2];\n\t    /* If we've read a whole chunk, read a CRLF */\n\t    readlen = ne_sock_fullread(sock, crlfbuf, 2);\n            if (readlen < 0)\n                return aborted(req, _(\"Could not read chunk delimiter\"),\n                               readlen);\n            else if (crlfbuf[0] != '\\r' || crlfbuf[1] != '\\n')\n                return aborted(req, _(\"Chunk delimiter was invalid\"), 0);\n\t}\n    } else if (resp->mode == R_CLENGTH) {\n\tresp->body.clen.remain -= readlen;\n    }\n    resp->progress += readlen;\n    return NE_OK;\n}\n\nssize_t ne_read_response_block(ne_request *req, char *buffer, size_t buflen)\n{\n    struct body_reader *rdr;\n    struct ne_response *const resp = &req->resp;\n    ne_session_status_info *const info = &req->session->status;\n\n    if (read_response_block(req, resp, buffer, &buflen))\n\treturn -1;\n\n    if (buflen) {\n        info->sr.progress += buflen;\n        notify_status(req->session, ne_status_recving);\n    }\n    else if (info->sr.total == -1) {\n        info->sr.total = info->sr.progress;\n        notify_status(req->session, ne_status_recving);\n    }\n\n    for (rdr = req->body_readers; rdr!=NULL; rdr=rdr->next) {\n\tif (rdr->use && rdr->handler(rdr->userdata, buffer, buflen) != 0) {\n            ne_close_connection(req->session);\n            return -1;\n        }\n    }\n    \n    return buflen;\n}\n\n/* Build the request string, returning the buffer. */\nstatic ne_buffer *build_request(ne_request *req) \n{\n    struct hook *hk;\n    ne_buffer *buf = ne_buffer_create();\n\n    /* Add Request-Line and headers: */\n    ne_buffer_concat(buf, req->method, \" \", req->target, \" HTTP/1.1\" EOL,\n                     NULL);\n\n    /* Add custom headers: */\n    ne_buffer_append(buf, req->headers->data, ne_buffer_size(req->headers));\n\n    if (req->body_length && req->flags[NE_REQFLAG_EXPECT100]) {\n        ne_buffer_czappend(buf, \"Expect: 100-continue\\r\\n\");\n    }\n\n    NE_DEBUG(NE_DBG_HTTP, \"Running pre_send hooks\\n\");\n    for (hk = req->session->pre_send_hooks; hk!=NULL; hk = hk->next) {\n\tne_pre_send_fn fn = (ne_pre_send_fn)hk->fn;\n\tfn(req, hk->userdata, buf);\n    }\n    \n    ne_buffer_czappend(buf, \"\\r\\n\");\n    return buf;\n}\n\n#ifdef NE_DEBUGGING\n#define DEBUG_DUMP_REQUEST(x) dump_request(x)\n\nstatic void dump_request(const char *request)\n{ \n    if (ne_debug_mask & NE_DBG_HTTPPLAIN) { \n\t/* Display everything mode */\n\tNE_DEBUG(NE_DBG_HTTP, \"Sending request headers:\\n%s\", request);\n    } else if (ne_debug_mask & NE_DBG_HTTP) {\n\t/* Blank out the Authorization parameters */\n\tchar *reqdebug = ne_strdup(request), *pnt = reqdebug;\n\twhile ((pnt = strstr(pnt, \"Authorization: \")) != NULL) {\n\t    for (pnt += 15; *pnt != '\\r' && *pnt != '\\0'; pnt++) {\n\t\t*pnt = 'x';\n\t    }\n\t}\n\tNE_DEBUG(NE_DBG_HTTP, \"Sending request headers:\\n%s\", reqdebug);\n\tne_free(reqdebug);\n    }\n}\n\n#else\n#define DEBUG_DUMP_REQUEST(x)\n#endif /* DEBUGGING */\n\n/* Read and parse response status-line into 'status'.  'retry' is non-zero\n * if an NE_RETRY should be returned if an EOF is received. */\nstatic int read_status_line(ne_request *req, ne_status *status, int retry)\n{\n    char *buffer = req->respbuf;\n    ssize_t ret;\n\n    ret = read_message_line(req->session->socket, buffer, sizeof req->respbuf);\n    if (ret <= 0) {\n        int aret = aborted(req, _(\"Could not read status line\"), ret);\n        return RETRY_RET(retry, ret, aret);\n    }\n    \n    if (status->reason_phrase) ne_free(status->reason_phrase);\n    memset(status, 0, sizeof *status);\n\n    /* Hack to allow ShoutCast-style servers, if requested. */\n    if (req->session->flags[NE_SESSFLAG_ICYPROTO]\n        && strncmp(buffer, \"ICY \", 4) == 0 && strlen(buffer) > 8\n        && buffer[7] == ' ') {\n        status->code = atoi(buffer + 4);\n        status->major_version = 1;\n        status->minor_version = 0;\n        status->reason_phrase = ne_strclean(ne_strdup(buffer + 8));\n        status->klass = buffer[4] - '0';\n        NE_DEBUG(NE_DBG_HTTP, \"[status-line] ICY protocol; code %d\\n\", \n                 status->code);\n        return 0;\n    }\n\n    if (ne_parse_statusline(buffer, status)) {\n\treturn aborted(req, _(\"Could not parse response status line\"), 0);\n    }\n    if (status->major_version != 1) {\n        return aborted(req, _(\"Incompatible HTTP version\"), 0);\n    }\n\n    return 0;\n}\n\n#define INTERIM_TIMEOUT(req_) \\\n    (((req_)->flags[NE_REQFLAG_1XXTIMEOUT] && (req_)->session->rdtimeout) \\\n      ? time(NULL) + (req_)->session->rdtimeout : 0)\n\n/* Send the request, and read the response Status-Line. Returns:\n *   NE_RETRY   connection closed by server; persistent connection\n *\t\ttimeout\n *   NE_OK\tsuccess\n *   NE_*\terror\n * On NE_RETRY and NE_* responses, the connection will have been \n * closed already.\n */\nstatic int send_request(ne_request *req, const ne_buffer *request)\n{\n    ne_session *const sess = req->session;\n    ne_status *const status = &req->status;\n    int sentbody = 0; /* zero until body has been sent. */\n    int ret, retry; /* retry non-zero whilst the request should be retried */\n    time_t timeout = INTERIM_TIMEOUT(req);\n    ssize_t sret;\n\n    /* Send the Request-Line and headers */\n    NE_DEBUG(NE_DBG_HTTP, \"Sending request-line and headers:\\n\");\n    /* Open the connection if necessary */\n    ret = open_connection(sess);\n    if (ret) return ret;\n\n    /* Allow retry if a persistent connection has been used. */\n    retry = sess->persisted;\n    \n    sret = ne_sock_fullwrite(req->session->socket, request->data, \n                             ne_buffer_size(request));\n    if (sret < 0) {\n\tint aret = aborted(req, _(\"Could not send request\"), sret);\n\treturn RETRY_RET(retry, sret, aret);\n    }\n    \n    if (!req->flags[NE_REQFLAG_EXPECT100] && req->body_length) {\n\t/* Send request body, if not using 100-continue. */\n\tret = send_request_body(req, retry);\n\tif (ret) {\n            return ret;\n\t}\n    }\n    \n    NE_DEBUG(NE_DBG_HTTP, \"Request sent; retry is %d.\\n\", retry);\n\n    /* Loop eating interim 1xx responses; RFC 7231§6.2 says clients\n     * MUST be able to parse unsolicited interim responses. */\n    while ((ret = read_status_line(req, status, retry)) == NE_OK\n           && status->klass == 1) {\n        struct interim_handler *ih;\n\n\tNE_DEBUG(NE_DBG_HTTP, \"[req] Interim %d response.\\n\", status->code);\n\tretry = 0; /* successful read() => never retry now. */\n\n\t/* Discard headers with the interim response. */\n\tif ((ret = read_response_headers(req)) != NE_OK) break;\n\n        /* Run interim handlers. */\n        for (ih = req->interim_handler; ih; ih = ih->next) {\n            ih->fn(ih->userdata, req, status);\n        }\n\n\tif (req->flags[NE_REQFLAG_EXPECT100] && (status->code == 100)\n            && req->body_length && !sentbody) {\n\t    /* Send the body after receiving the first 100 Continue */\n\t    if ((ret = send_request_body(req, 0)) != NE_OK) break;\t    \n\t    sentbody = 1;\n            /* Reset read timeout. */\n            timeout = INTERIM_TIMEOUT(req);\n\t}\n        else if (req->flags[NE_REQFLAG_1XXTIMEOUT] && sess->rdtimeout\n                 && time(NULL) > timeout) {\n            NE_DEBUG(NE_DBG_HTTP, \"[req] Timeout after %d\\n\", sess->rdtimeout);\n            return aborted(req, _(\"Timed out reading interim responses\"), 0);\n        }\n    }\n\n    /* Per RFC 9110§15.5.9 a client MAY retry an outstanding request\n     * after a 408. Some modern servers generate this. */\n    if (sess->persisted && status->code == 408) {\n        NE_DEBUG(NE_DBG_HTTP, \"req: Retrying after 408.\\n\");\n        ne_close_connection(sess);\n        return NE_RETRY;\n    }\n\n    return ret;\n}\n\n/* Read a message header from sock into buf, which has size 'buflen'.\n *\n * Returns:\n *   NE_RETRY: Success, read a header into buf.\n *   NE_OK: End of headers reached.\n *   NE_ERROR: Error (session error is set, connection closed).\n */\nstatic int read_message_header(ne_request *req, char *buf, size_t buflen)\n{\n    ssize_t n;\n    ne_socket *sock = req->session->socket;\n\n    n = read_message_line(sock, buf, buflen);\n    if (n < 0) {\n        return aborted(req, _(\"Error reading response headers\"), n);\n    }\n    else if (n == 0) {\n        NE_DEBUG(NE_DBG_HTTP, \"req: End of headers.\\n\");\n        return NE_OK;\n    }\n\n    /* Per RFC9112§5.2, append any folded headers extended over\n     * multiple lines (if there is space in the buffer). */\n    while ((size_t)n < buflen) {\n        char ch;\n\n        buf += n;\n        buflen -= n;\n\n        /* Collect any extra lines into buffer */\n        n = ne_sock_peek(sock, &ch, 1);\n        if (n <= 0) {\n            return aborted(req, _(\"Error reading response headers\"), n);\n        }\n\n\tif (ch != ' ' && ch != '\\t') {\n\t    /* No continuation of this header: stop reading. */\n\t    return NE_RETRY;\n\t}\n\n\t/* Otherwise, read the next line onto the end of 'buf'. */\n\tn = read_message_line(sock, buf, buflen);\n\tif (n <= 0) {\n\t    return aborted(req, _(\"Error reading response headers\"), n);\n\t}\n\n        buf[0] = ' '; /* replacing \\t */\n    }\n\n    ne_set_error(req->session, _(\"Response header too long\"));\n    return NE_ERROR;\n}\n\n#define MAX_HEADER_LEN (8192)\n\n#define add_response_header(req_, hash, name, value) \\\n    add_field(&(req_)->response_headers, (hash), (name), (value))\n\n/* Add a response header field, using precalculated hash value. The\n * fields parameter is a pointer to a pointer to an array of pointers;\n * *fields may be NULL in which case it is lazily-initialized on\n * demand. */\nstatic void add_field(field_hash **fh, unsigned int hash,\n                      const char *name, char *value)\n{\n    struct field **nextf;\n    size_t vlen = strlen(value);\n\n    if (*fh == NULL) *fh = ne_calloc(sizeof **fh);\n    nextf = &(**fh)[hash];\n\n    while (*nextf) {\n        struct field *const f = *nextf;\n        if (strcmp(f->name, name) == 0) {\n            if (vlen + f->vlen < MAX_HEADER_LEN) {\n                /* merge the header field */\n                f->value = ne_realloc(f->value, f->vlen + vlen + 3);\n                memcpy(f->value + f->vlen, \", \", 2);\n                memcpy(f->value + f->vlen + 2, value, vlen + 1);\n                f->vlen += vlen + 2;\n            }\n            return;\n        }\n        nextf = &f->next;\n    }\n    \n    (*nextf) = ne_malloc(sizeof **nextf);\n    (*nextf)->name = ne_strdup(name);\n    (*nextf)->value = ne_strdup(value);\n    (*nextf)->vlen = vlen;\n    (*nextf)->next = NULL;\n}\n\n/* HTTP token lookup per RFC9110§5.6.2 - returns tolower(ch) or 0 for\n * non-token characters. */\n\n/* Generated with 'mktable http_token', do not alter here -- */\nstatic const unsigned char table_http_token[256] = {\n/* x00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n/* x08 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n/* x10 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n/* x18 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n/* x20 */ 0x00, 0x21, 0x00, 0x23, 0x24, 0x25, 0x26, 0x27,\n/* x28 */ 0x00, 0x00, 0x2a, 0x2b, 0x00, 0x2d, 0x2e, 0x00,\n/* x30 */ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,\n/* x38 */ 0x38, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n/* x40 */ 0x00, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,\n/* x48 */ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,\n/* x50 */ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,\n/* x58 */ 0x78, 0x79, 0x7a, 0x00, 0x00, 0x00, 0x5e, 0x5f,\n/* x60 */ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,\n/* x68 */ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,\n/* x70 */ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,\n/* x78 */ 0x78, 0x79, 0x7a, 0x00, 0x7c, 0x00, 0x7e, 0x00,\n/* x80 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n/* x88 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n/* x90 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n/* x98 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n/* xA0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n/* xA8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n/* xB0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n/* xB8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n/* xC0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n/* xC8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n/* xD0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n/* xD8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n/* xE0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n/* xE8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n/* xF0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n/* xF8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\n}; /* -- Generated code from 'mktable http_token' ends. */\n\n/* Read headers into fields. Returns NE_* code, sets session error and\n * closes connection on error. */\nstatic int read_header_fields(ne_request *req, field_hash **fields)\n{\n    char hdr[MAX_HEADER_LEN];\n    int ret, count = 0;\n\n    while ((ret = read_message_header(req, hdr, sizeof hdr)) == NE_RETRY \n           && ++count < MAX_HEADER_FIELDS) {\n        char *pnt, ch;\n        unsigned int hash = 0;\n\n        /* Parse field-line per RFC9110§5:\n         *    field-line   = field-name \":\" OWS field-value OWS\n         * where field-name is defined as a token, RFC9110§5.1. */\n\n        /* Strip trailing OWS */\n        pnt = hdr + strlen(hdr) - 1;\n        while (pnt > hdr && (*pnt == ' ' || *pnt == '\\t'))\n            *pnt-- = '\\0';\n\n        /* Parse and convert to lower-case a single token. */\n        for (pnt = hdr;\n             (ch = table_http_token[(unsigned char)*pnt]) != 0;\n             pnt++) {\n            *pnt = ch; /* lowercased character */\n            hash = HH_ITERATE(hash, *pnt);\n        }\n\n        /* Ignore header lines where ':' is not directly after the\n         * token (per RFC9112§5.1). */\n        if (pnt[0] != ':') {\n            NE_DEBUG(NE_DBG_HTTP, \"req: Ignoring invalid field %s\\n\", hdr);\n            continue;\n        }\n\n        /* NUL-terminate field-name at the colon. */\n        *pnt++ = '\\0';\n\n        /* Skip any whitespace after the colon... */\n        while (*pnt == ' ' || *pnt == '\\t')\n            pnt++;\n\n        /* pnt now points to the header value. */\n        NE_DEBUG(NE_DBG_HTTP, \"req: Header: [%s] = [%s]\\n\", hdr, pnt);\n        add_field(fields, hash, hdr, pnt);\n    }\n\n    if (count == MAX_HEADER_FIELDS)\n\tret = aborted(\n\t    req, _(\"Response exceeded maximum number of header fields\"), 0);\n\n    return ret;\n}\n\n/* Perform any necessary DNS lookup for the host given by *info;\n * returns NE_ code with error string set on error. */\nstatic int lookup_host(ne_session *sess, struct host_info *info)\n{\n    NE_DEBUG(NE_DBG_HTTP, \"Doing DNS lookup on %s...\\n\", info->hostname);\n    sess->status.lu.hostname = info->hostname;\n    notify_status(sess, ne_status_lookup);\n    info->address = ne_addr_resolve(info->hostname, 0);\n    if (ne_addr_result(info->address)) {\n\tchar buf[256];\n\tne_set_error(sess, _(\"Could not resolve hostname `%s': %s\"), \n\t\t     info->hostname,\n\t\t     ne_addr_error(info->address, buf, sizeof buf));\n\tne_addr_destroy(info->address);\n\tinfo->address = NULL;\n\treturn NE_LOOKUP;\n    } else {\n\treturn NE_OK;\n    }\n}\n\nint ne_begin_request(ne_request *req)\n{\n    struct body_reader *rdr;\n    ne_buffer *data;\n    const ne_status *const st = &req->status;\n    const char *value;\n    struct hook *hk;\n    int ret, forced_closure = 0;\n\n    /* If a non-idempotent request is sent on a persisted connection,\n     * then it is impossible to distinguish between a server failure\n     * and a connection timeout if an EOF/RST is received.  So don't\n     * do that. */\n    if (!req->flags[NE_REQFLAG_IDEMPOTENT] && req->session->persisted\n        && !req->session->flags[NE_SESSFLAG_CONNAUTH]) {\n        NE_DEBUG(NE_DBG_HTTP, \"req: Closing connection for non-idempotent \"\n                 \"request.\\n\");\n        ne_close_connection(req->session);\n    }\n\n    /* Build the request string, and send it */\n    data = build_request(req);\n    DEBUG_DUMP_REQUEST(data->data);\n    ret = send_request(req, data);\n    /* Retry this once after a persistent connection timeout. */\n    if (ret == NE_RETRY) {\n\tNE_DEBUG(NE_DBG_HTTP, \"req: Persistent connection timed out, retrying.\\n\");\n\tret = send_request(req, data);\n    }\n    ne_buffer_destroy(data);\n    if (ret != NE_OK) return ret == NE_RETRY ? NE_ERROR : ret;\n\n    /* HTTP/1.x is assured by read_status_line() not failing.\n     * Persistent connections supported implicitly in HTTP/1.1. */\n    req->can_persist = req->session->is_http11 = st->minor_version > 0;\n\n    ne_set_error(req->session, \"%d %s\", st->code, st->reason_phrase);\n\n    /* Read response headers. */\n    ret = read_response_headers(req);\n    if (ret) return ret;\n\n    /* check the Connection header */\n    value = get_response_header_hv(req, HH_HV_CONNECTION, \"connection\");\n    if (value) {\n        char *vcopy = ne_strdup(value), *ptr = vcopy;\n\n        do {\n            char *token = ne_shave(ne_token(&ptr, ','), \" \\t\");\n            unsigned int hash = hash_and_lower(token);\n\n            if (strcmp(token, \"close\") == 0) {\n                req->can_persist = 0;\n                forced_closure = 1;\n            } else if (strcmp(token, \"keep-alive\") == 0) {\n                req->can_persist = 1;\n            } else if (!req->session->is_http11\n                       && strcmp(token, \"connection\")) {\n                /* Strip the header per 2616§14.10, last para.  Avoid\n                 * danger from \"Connection: connection\". */\n                remove_response_header(req, token, hash);\n            }\n        } while (ptr);\n        \n        ne_free(vcopy);\n    }\n\n    /* Support \"Proxy-Connection: keep-alive\" for compatibility with\n     * some HTTP/1.0 proxies; it is risky to do this, because an\n     * intermediary proxy may not support this HTTP/1.0 extension, but\n     * will not strip the header either.  Persistent connection\n     * support is enabled based on the presence of this header if:\n     * a) it is *necessary* to do so due to the use of a connection-auth\n     * scheme, and\n     * b) connection closure was not forced via \"Connection: close\".  */\n    if (req->session->nexthop->proxy == PROXY_HTTP && !req->session->is_http11\n        && !forced_closure && req->session->flags[NE_SESSFLAG_CONNAUTH]) {\n        value = get_response_header_hv(req, HH_HV_PROXY_CONNECTION,\n                                       \"proxy-connection\");\n        if (value && ne_strcasecmp(value, \"keep-alive\") == 0) {\n            NE_DEBUG(NE_DBG_HTTP, \"req: Using persistent connection \"\n                     \"for HTTP/1.0 proxy requiring conn-auth hack.\\n\");\n            req->can_persist = 1;\n        }\n    }\n\n    /* Decide which method determines the response message-length per\n     * RFC 9112§6.3, cases follow: */\n#ifdef NE_HAVE_SSL\n    /* Case (2) is special-cased first for CONNECT: the response has\n     * no body, and the connection can persist. */\n    if (req->session->in_connect && st->klass == 2) {\n\treq->resp.mode = R_NO_BODY;\n\treq->can_persist = 1;\n    } else\n#endif\n    /* Case (1), HEAD requests and 204, 304 responses have no response\n     * body, regardless of what headers are present. */\n    if (req->method_is_head || st->code == 204 || st->code == 304) {\n    \treq->resp.mode = R_NO_BODY;\n    }\n    /* Case (3)/(4), chunked transfer-encoding. */\n    else if ((value = get_response_header_hv(req, HH_HV_TRANSFER_ENCODING,\n                                             \"transfer-encoding\")) != NULL\n             && ne_strcasecmp(value, \"identity\") != 0) {\n        /* Otherwise, fail if an unknown transfer-coding is used, no\n         * other transfer-codings are supported. */\n        if (ne_strcasecmp(value, \"chunked\") == 0) {\n            req->resp.mode = R_CHUNKED;\n            req->resp.body.chunk.remain = 0;\n        }\n        else {\n            return aborted(req, _(\"Unknown transfer-coding in response\"), 0);\n        }\n    }\n    /* Case (5)/(6), content-length delimited. */\n    else if ((value = get_response_header_hv(req, HH_HV_CONTENT_LENGTH,\n                                             \"content-length\")) != NULL) {\n        char *endptr = NULL;\n        ne_off_t len = ne_strtoff(value, &endptr, 10);\n\n        if (*value && len != NE_OFFT_MAX && len >= 0 && endptr && *endptr == '\\0') {\n            req->resp.mode = R_CLENGTH;\n            req->resp.body.clen.total = req->resp.body.clen.remain = len;\n        }\n        else {\n            /* Per case (5), an invalid C-L MUST be treated as an error. */\n            return aborted(req, _(\"Invalid Content-Length in response\"), 0);\n        }\n    }\n    /* Case (8), response delimited by EOF. */\n    else {\n        req->resp.mode = R_TILLEOF; /* otherwise: read-till-eof mode */\n    }\n    \n    NE_DEBUG(NE_DBG_HTTP, \"Running post_headers hooks\\n\");\n    for (hk = req->session->post_headers_hooks; hk != NULL; hk = hk->next) {\n        ne_post_headers_fn fn = (ne_post_headers_fn)hk->fn;\n        fn(req, hk->userdata, &req->status);\n    }\n    \n    /* Prepare for reading the response entity-body.  Call each of the\n     * body readers and ask them whether they want to accept this\n     * response or not. */\n    for (rdr = req->body_readers; rdr != NULL; rdr=rdr->next) {\n\trdr->use = rdr->accept_response(rdr->userdata, req, st);\n    }\n\n    req->session->status.sr.progress = 0;\n    req->session->status.sr.total = \n        req->resp.mode == R_CLENGTH ? req->resp.body.clen.total : -1;\n    notify_status(req->session, ne_status_recving);\n    \n    return NE_OK;\n}\n\nint ne_end_request(ne_request *req)\n{\n    struct hook *hk;\n    int ret = NE_OK;\n\n    if (req->resp.mode == R_CHUNKED) {\n        /* Read headers in chunked trailer, lazy-init the array. Per\n         * RFC9110§6.5, trailer fields are stored separately. */\n        ret = read_header_fields(req, &req->response_trailers);\n        if (ret) return ret;\n    }\n    \n    NE_DEBUG(NE_DBG_HTTP, \"Running post_send hooks\\n\");\n    for (hk = req->session->post_send_hooks; \n\t ret == NE_OK && hk != NULL; hk = hk->next) {\n\tne_post_send_fn fn = (ne_post_send_fn)hk->fn;\n\tret = fn(req, hk->userdata, &req->status);\n    }\n\n    /* Close the connection if persistent connections are disabled or\n     * not supported by the server. */\n    if (!req->session->flags[NE_SESSFLAG_PERSIST] || !req->can_persist)\n\tne_close_connection(req->session);\n    else\n\treq->session->persisted = 1;\n    \n    return ret;\n}\n\nint ne_read_response_to_fd(ne_request *req, int fd)\n{\n    ssize_t len;\n\n    while ((len = ne_read_response_block(req, req->respbuf, \n                                         sizeof req->respbuf)) > 0) {\n        const char *block = req->respbuf;\n\n        do {\n            ssize_t ret = write(fd, block, len);\n            if (ret == -1 && errno == EINTR) {\n                continue;\n            } else if (ret < 0) {\n                char err[200];\n                ne_strerror(errno, err, sizeof err);\n                ne_set_error(ne_get_session(req), \n                             _(\"Could not write to file: %s\"), err);\n                return NE_ERROR;\n            } else {\n                len -= ret;\n                block += ret;\n            }\n        } while (len > 0);\n    }\n    \n    return len == 0 ? NE_OK : NE_ERROR;\n}\n\nint ne_read_response_to_buffer(ne_request *req, char *buf, size_t *buflen)\n{\n    size_t remain = *buflen;\n    ssize_t rlen = -1;\n    char ch, *ptr = buf;\n    int ret = NE_OK;\n\n    while (ret == NE_OK && remain) {\n        rlen = ne_read_response_block(req, ptr, remain);\n        if (rlen > 0) {\n            remain -= rlen;\n            ptr += rlen;\n        }\n        else if (rlen == 0) {\n            *buflen = ptr - buf;\n            break;\n        }\n        else if (rlen < 0) {\n            ret = NE_ERROR;\n        }\n    }\n\n    /* If the buffer was filled, check whether the entire response\n     * body has been read, and fail with NE_FAILED if not. */\n    if (ret == NE_OK && remain == 0 && rlen > 0) {\n        if ((rlen = ne_read_response_block(req, &ch, sizeof ch)) == 0)\n            *buflen = ptr - buf; /* success, entire response read. */\n        else if (rlen < 0)\n            ret = NE_ERROR;\n        else /* rlen > 0 => more response to read, fail */ {\n            ret = NE_FAILED;\n            ne_set_error(req->session, _(\"Response buffer size too small\"));\n        }\n    }\n\n    return ret;\n}\n\nint ne_discard_response(ne_request *req)\n{\n    ssize_t len;\n\n    do {\n        len = ne_read_response_block(req, req->respbuf, sizeof req->respbuf);\n    } while (len > 0);\n    \n    return len == 0 ? NE_OK : NE_ERROR;\n}\n\nint ne_request_dispatch(ne_request *req) \n{\n    int ret;\n    \n    do {\n\tret = ne_begin_request(req);\n        if (ret == NE_OK) ret = ne_discard_response(req);\n        if (ret == NE_OK) ret = ne_end_request(req);\n    } while (ret == NE_RETRY);\n\n    NE_DEBUG(NE_DBG_HTTP | NE_DBG_FLUSH, \n             \"Request ends, status %d class %dxx, error line:\\n%s\\n\", \n             req->status.code, req->status.klass, req->session->error);\n\n    return ret;\n}\n\nconst ne_status *ne_get_status(const ne_request *req)\n{\n    return &req->status;\n}\n\nne_session *ne_get_session(const ne_request *req)\n{\n    return req->session;\n}\n\n#ifdef NE_HAVE_SSL\n/* Create a CONNECT tunnel through the proxy server.\n * Returns HTTP_* */\nstatic int proxy_tunnel(ne_session *sess)\n{\n    /* Hack up an HTTP CONNECT request... */\n    ne_request *req;\n    int ret = NE_OK;\n    char ruri[200];\n\n    /* Can't use server.hostport here; Request-URI must include `:port' */\n    ne_snprintf(ruri, sizeof ruri, \"%s:%u\", sess->server.hostname,  \n\t\tsess->server.port);\n    req = ne_request_create(sess, \"CONNECT\", ruri);\n\n    sess->in_connect = 1;\n    ret = ne_request_dispatch(req);\n    sess->in_connect = 0;\n\n    sess->persisted = 0; /* don't treat this is a persistent connection. */\n\n    if (ret != NE_OK || !sess->connected || req->status.klass != 2) {\n        char *err = ne_strdup(sess->error);\n        ne_set_error(sess, _(\"Could not create SSL connection \"\n                             \"through proxy server: %s\"), err);\n        ne_free(err);\n        if (ret == NE_OK) ret = NE_ERROR;\n    }\n\n    ne_request_destroy(req);\n    return ret;\n}\n#endif\n\n/* Return the first resolved address for the given host. */\nstatic const ne_inet_addr *resolve_first(struct host_info *host)\n{\n    return host->network ? host->network : ne_addr_first(host->address);\n}\n\n/* Return the next resolved address for the given host or NULL if\n * there are no more addresses. */\nstatic const ne_inet_addr *resolve_next(struct host_info *host)\n{\n    return host->network ? NULL : ne_addr_next(host->address);\n}\n\n/* Make new TCP connection to server at 'host' of type 'name'.  Note\n * that once a connection to a particular network address has\n * succeeded, that address will be used first for the next attempt to\n * connect. */\nstatic int do_connect(ne_session *sess, struct host_info *host)\n{\n    int ret;\n\n    /* Resolve hostname if necessary. */\n    if (host->address == NULL && host->network == NULL) {\n        ret = lookup_host(sess, host);\n        if (ret) return ret;\n    }\n\n    if ((sess->socket = ne_sock_create()) == NULL) {\n        ne_set_error(sess, _(\"Could not create socket\"));\n        return NE_ERROR;\n    }\n\n    if (sess->cotimeout)\n\tne_sock_connect_timeout(sess->socket, sess->cotimeout);\n\n    if (sess->local_addr)\n        ne_sock_prebind(sess->socket, sess->local_addr, 0);\n\n    /* Pick the first address, or if the address was pre-determined\n       (e.g. an IP-literal passed to ne_session_create) fetch that. */\n    if (host->current == NULL)\n\thost->current = resolve_first(host);\n\n    sess->status.ci.hostname = host->hostname;\n\n    do {\n        sess->status.ci.address = host->current;\n\tnotify_status(sess, ne_status_connecting);\n#ifdef NE_DEBUGGING\n\tif (ne_debug_mask & NE_DBG_HTTP) {\n\t    char buf[150];\n\t    NE_DEBUG(NE_DBG_HTTP, \"req: Connecting to %s:%u\\n\",\n\t\t     ne_iaddr_print(host->current, buf, sizeof buf),\n                     host->port);\n\t}\n#endif\n\tret = ne_sock_connect(sess->socket, host->current, host->port);\n    } while (ret && /* try the next address... */\n\t     (host->current = resolve_next(host)) != NULL);\n\n    if (ret) {\n        const char *msg;\n\n        if (host->proxy == PROXY_NONE)\n            msg = _(\"Could not connect to server\");\n        else\n            msg = _(\"Could not connect to proxy server\");\n\n        ne_set_error(sess, \"%s: %s\", msg, ne_sock_error(sess->socket));\n        ne_sock_close(sess->socket);\n\treturn ret == NE_SOCK_TIMEOUT ? NE_TIMEOUT : NE_CONNECT;\n    }\n\n    if (sess->rdtimeout)\n\tne_sock_read_timeout(sess->socket, sess->rdtimeout);\n\n    notify_status(sess, ne_status_connected);\n    sess->nexthop = host;\n\n    sess->connected = 1;\n    /* clear persistent connection flag. */\n    sess->persisted = 0;\n    return NE_OK;\n}\n\n/* For a SOCKSv4 proxy only, the IP address of the origin server (in\n * addition to the proxy) must be known, and must be an IPv4 address.\n * Returns NE_*; connection closed and error string set on error. */\nstatic int socks_origin_lookup(ne_session *sess)\n{\n    const ne_inet_addr *ia;\n    int ret;\n\n    ret = lookup_host(sess, &sess->server);\n    if (ret) {\n        /* lookup_host already set the error string. */\n        ne_close_connection(sess);\n        return ret;\n    }\n    \n    /* Find the first IPv4 address available for the server. */\n    for (ia = ne_addr_first(sess->server.address);\n         ia && ne_iaddr_typeof(ia) == ne_iaddr_ipv6;\n         ia = ne_addr_next(sess->server.address)) {\n        /* noop */\n    }\n\n    /* ... if any */\n    if (ia == NULL) {\n        ne_set_error(sess, _(\"Could not find IPv4 address of \"\n                             \"hostname %s for SOCKS v4 proxy\"), \n                     sess->server.hostname);\n        ne_close_connection(sess);\n        return NE_LOOKUP;\n    }\n\n    sess->server.current = ia;\n    \n    return ret;\n}\n\nstatic int open_connection(ne_session *sess) \n{\n    int ret;\n    \n    if (sess->connected) return NE_OK;\n\n    if (!sess->proxies) {\n        ret = do_connect(sess, &sess->server);\n        if (ret) {\n            sess->nexthop = NULL;\n            return ret;\n        }\n    }\n    else {\n        struct host_info *hi;\n\n        /* Attempt to re-use proxy to avoid iterating through\n         * unnecessarily. */\n        if (sess->prev_proxy) \n            ret = do_connect(sess, sess->prev_proxy);\n        else\n            ret = NE_ERROR;\n\n        /* Otherwise, try everything - but omitting prev_proxy if that\n         * has already been tried. */\n        for (hi = sess->proxies; hi && ret; hi = hi->next) {\n            if (hi != sess->prev_proxy)\n                ret = do_connect(sess, hi);\n        }\n\n        if (ret == NE_OK && sess->nexthop->proxy == PROXY_SOCKS) {\n            /* Special-case for SOCKS v4 proxies, which require the\n             * client to resolve the origin server IP address. */\n            if (sess->socks_ver == NE_SOCK_SOCKSV4) {\n                ret = socks_origin_lookup(sess);\n            }\n            \n            if (ret == NE_OK) {\n                /* Perform the SOCKS handshake, instructing the proxy\n                 * to set up the connection to the origin server. */\n                ret = ne_sock_proxy(sess->socket, sess->socks_ver, \n                                    sess->server.current,\n                                    sess->server.hostname, sess->server.port,\n                                    sess->socks_user, sess->socks_password);\n                if (ret) {\n                    ne_set_error(sess, \n                                 _(\"Could not establish connection from \"\n                                   \"SOCKS proxy (%s:%u): %s\"),\n                                 sess->nexthop->hostname,\n                                 sess->nexthop->port,\n                                 ne_sock_error(sess->socket));\n                    ne_close_connection(sess);\n                    ret = NE_ERROR;\n                }\n            }\n        }\n\n        if (ret != NE_OK) {\n            sess->nexthop = NULL;\n            sess->prev_proxy = NULL;\n            return ret;\n        }\n        \n        /* Success - make this proxy stick. */\n        sess->prev_proxy = hi;\n    }\n\n#ifdef NE_HAVE_SSL\n    /* Negotiate SSL layer if required. */\n    if (sess->use_ssl && !sess->in_connect) {\n        /* Set up CONNECT tunnel if using an HTTP proxy. */\n        if (sess->nexthop->proxy == PROXY_HTTP)\n            ret = proxy_tunnel(sess);\n\n        if (ret == NE_OK) ret = ne__negotiate_ssl(sess);\n        if (ret != NE_OK) ne_close_connection(sess);\n    }\n#endif\n    \n    return ret;\n}\n"
  },
  {
    "path": "src/ne_request.h",
    "content": "/* \n   HTTP Request Handling\n   Copyright (C) 1999-2026, Joe Orton <joe@manyfish.co.uk>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n   \n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n\n#ifndef NE_REQUEST_H\n#define NE_REQUEST_H\n\n#include \"ne_utils.h\" /* For ne_status */\n#include \"ne_string.h\" /* For ne_buffer */\n#include \"ne_session.h\"\n\nNE_BEGIN_DECLS\n\n#define NE_OK (0) /* Success */\n#define NE_ERROR (1) /* Generic error; use ne_get_error(session) for message */\n#define NE_LOOKUP (2) /* Server or proxy hostname lookup failed */\n#define NE_AUTH (3) /* User authentication failed on server */\n#define NE_PROXYAUTH (4) /* User authentication failed on proxy */\n#define NE_CONNECT (5) /* Could not connect to server */\n#define NE_TIMEOUT (6) /* Connection timed out */\n#define NE_FAILED (7) /* The precondition failed */\n#define NE_RETRY (8) /* Retry request (ne_end_request ONLY) */\n#define NE_REDIRECT (9) /* See ne_redirect.h */\n\n/* Opaque object representing a single HTTP request. */\ntypedef struct ne_request_s ne_request;\n\n/***** Request Handling *****/\n\n/* Create a request in session 'sess', with given method and target.\n * 'target' is used to form the request-target (per RFC 9112ẞ3.2), and\n * may be an absolute-path (with optional query-string), an\n * absolute-URI, or an asterisk. */\nne_request *ne_request_create(ne_session *sess, const char *method,\n                              const char *target)\n    ne_attribute((nonnull));\n\n/* The request body will be taken from 'size' bytes of 'buffer'. */\nvoid ne_set_request_body_buffer(ne_request *req, const char *buffer,\n                                size_t size)\n    ne_attribute((nonnull));\n\n/* The request body will be taken from 'length' bytes read from the\n * file descriptor 'fd', starting from file offset 'offset'. */\nvoid ne_set_request_body_fd(ne_request *req, int fd,\n                            ne_off_t offset, ne_off_t length)\n    ne_attribute((nonnull));\n\n/* \"Pull\"-based request body provider: a callback which is invoked to\n * provide blocks of request body on demand.\n *\n * Before each time the body is provided, the callback will be called\n * once with buflen == 0.  The body may have to be provided >1 time\n * per request (for authentication retries etc.).\n *\n * For a call with buflen == 0, the callback must return zero on success\n * or non-zero on error; the session error string must be set on error.\n * For a call with buflen > 0, the callback must return:\n *        <0           : error, abort request; session error string must be set.\n *         0           : ignore 'buffer' contents, end of body.\n *     0 < x <= buflen : buffer contains x bytes of body data.  */\ntypedef ssize_t (*ne_provide_body)(void *userdata, char *buffer, size_t buflen);\n\n/* Install a callback which is invoked as needed to provide the\n * request body, a block at a time.  The total size of the request\n * body is 'length'; the callback must ensure that it returns no more\n * than 'length' bytes in total.  If 'length' is set to -1, then the\n * total size of the request is unknown by the caller and chunked\n * transfer will be used.\n *\n * The caller MUST determine that the server can accept chunked\n * encoding (i.e. advertises HTTP/1.1 support) before using chunked\n * encoding. This can be done by testing that ne_version_pre_http11()\n * returns zero after performing an OPTIONS or HEAD request. */\nvoid ne_set_request_body_provider(ne_request *req, ne_off_t length,\n                                  ne_provide_body provider, void *userdata)\n    ne_attribute((nonnull (1, 3)));\n\n/* Handling response bodies; two callbacks must be provided:\n *\n * 1) 'acceptance' callback: determines whether you want to handle the\n * response body given the response-status information, e.g., if you\n * only want 2xx responses, say so here.\n *\n * 2) 'reader' callback: passed blocks of the response-body as they\n * arrive, if the acceptance callback returned non-zero.  */\n\n/* 'acceptance' callback type. Return non-zero to accept the response,\n * else zero to ignore it. */\ntypedef int (*ne_accept_response)(void *userdata, ne_request *req, \n                                  const ne_status *st);\n\n/* An 'acceptance' callback which only accepts 2xx-class responses.\n * Ignores userdata. */\nint ne_accept_2xx(void *userdata, ne_request *req, const ne_status *st);\n\n/* An acceptance callback which accepts all responses.  Ignores\n * userdata. */\nint ne_accept_always(void *userdata, ne_request *req, const ne_status *st);\n\n/* Callback for reading a block of data.  Returns zero on success, or\n * non-zero on error.  If returning an error, the response will be\n * aborted and the callback will not be invoked again.  The request\n * dispatch (or ne_read_response_block call) will fail with NE_ERROR;\n * the session error string should have been set by the callback. */\ntypedef int (*ne_block_reader)(void *userdata, const char *buf, size_t len);\n\n/* Add a response reader for the given request, with the given\n * acceptance function. userdata is passed as the first argument to\n * the acceptance + reader callbacks. \n *\n * The acceptance callback is called once each time the request is\n * sent: it may be sent >1 time because of authentication retries etc.\n * For each time the acceptance callback is called, if it returns\n * non-zero, blocks of the response body will be passed to the reader\n * callback as the response is read.  After all the response body has\n * been read, the callback will be called with a 'len' argument of\n * zero.  */\nvoid ne_add_response_body_reader(ne_request *req, ne_accept_response accpt,\n\t\t\t\t ne_block_reader reader, void *userdata)\n    ne_attribute((nonnull (1, 2, 3)));\n\n/* Retrieve the value of the response header field with given name;\n * returns NULL if no response header with given name was found.  The\n * return value is valid only until the next call to either\n * ne_request_destroy or ne_begin_request for this request. */\nconst char *ne_get_response_header(ne_request *req, const char *name)\n    ne_attribute((nonnull));\n\n/* Retrieve the value of the response header field from any chunked\n * trailer with given name; returns NULL if no response header with\n * the given name was found.  The return value is valid only until the\n * next call to either ne_request_destroy or ne_begin_request for this\n * request. */\nconst char *ne_get_response_trailer(ne_request *req, const char *name)\n    ne_attribute((nonnull));\n\n/* Iterator interface for response headers: if passed a NULL cursor,\n * returns the first header; if passed a non-NULL cursor pointer,\n * returns the next header.  The return value is a cursor pointer: if\n * it is non-NULL, *name and *value are set to the name and value of\n * the header field.  If the return value is NULL, no more headers are\n * found, *name and *value are undefined.\n *\n * The order in which response headers is returned is undefined.  Both\n * the cursor and name/value pointers are valid only until the next\n * call to either ne_request_destroy or ne_begin_request for this\n * request. */\nvoid *ne_response_header_iterate(ne_request *req, void *cursor,\n                                 const char **name, const char **value);\n\n/* Iterator interface for response trailers; this has exactly the same\n * semantics as ne_response_header_iterate() except it operates on\n * fields in the trailer section (sent after a chunked response body)\n * rather than the header section (sent before any response body). */\nvoid *ne_response_trailer_iterate(ne_request *req, void *cursor,\n                                  const char **name, const char **value);\n\n/* Adds a header to the request with given name and value. */\nvoid ne_add_request_header(ne_request *req, const char *name, \n\t\t\t   const char *value);\n/* Adds a header to the request with given name, using printf-like\n * format arguments for the value. */\nvoid ne_print_request_header(ne_request *req, const char *name,\n\t\t\t     const char *format, ...) \n    ne_attribute((format(printf, 3, 4)));\n\n/* Returns the request target URI as a malloc-allocated ne_uri object,\n * or NULL on error if the request target cannot be determined. The\n * session error string is not changed on error. */\nconst ne_uri *ne_get_request_target(ne_request *req)\n    ne_attribute((nonnull));\n\n/* If the response includes a Location header, this function parses\n * and resolves the URI-reference relative to the request target.  If\n * a fragment (\"#fragment\") is used for the request target, it can be\n * passed as an argument to allow relative resolution. Returns a\n * malloc-allocated ne_uri object, or NULL if the URI in the Location\n * header could not be parsed, or the Location header was not\n * present. */\nne_uri *ne_get_response_location(ne_request *req, const char *fragment)\n    ne_attribute((nonnull (1)));\n\n/* If the response includes a Retry-After header, this function parses\n * the time given in the header value and returns it. If a relative\n * time is sent by the server, it will be handled relative to the time\n * when this function is called. If no header is present, or the\n * header value cannot be parsed, 0 is returned. */\ntime_t ne_get_response_retry_after(ne_request *req)\n    ne_attribute((nonnull (1)));\n\n/* ne_request_dispatch: Sends the given request, and reads the\n * response.  Returns:\n *  - NE_OK if the request was sent and response read successfully\n *  - NE_AUTH, NE_PROXYAUTH for a server or proxy server authentication error\n *  - NE_CONNECT if connection could not be established\n *  - NE_TIMEOUT if an timeout occurred sending or reading from the server\n *  - NE_ERROR for other fatal dispatch errors\n * On any error, the session error string is set.  On success or\n * authentication error, the actual response-status can be retrieved using\n * ne_get_status(). */\nint ne_request_dispatch(ne_request *req) ne_attribute((nonnull (1)));\n\n/* Returns a pointer to the response status information for the given\n * request; pointer is valid until request object is destroyed. */\nconst ne_status *ne_get_status(const ne_request *req) ne_attribute((const));\n\n/* Returns pointer to session associated with request. */\nne_session *ne_get_session(const ne_request *req) ne_attribute((const));\n\n/* Destroy memory associated with request pointer */\nvoid ne_request_destroy(ne_request *req);\n\n/* \"Caller-pulls\" request interface.  This is an ALTERNATIVE interface\n * to ne_request_dispatch: either use that, or do all this yourself:\n *\n * caller must call:\n *  1. ne_begin_request (fail if returns non-NE_OK)\n *  2. while(ne_read_response_block(...) > 0) ... loop ...;\n *     (fail if ne_read_response_block returns <0)\n *  3. ne_end_request\n *\n * ne_end_request and ne_begin_request both return an NE_* code; if\n * ne_end_request returns NE_RETRY, you must restart the loop from (1)\n * above. */\nint ne_begin_request(ne_request *req);\nint ne_end_request(ne_request *req);\n\n/* Read a block of the response into the passed buffer of size 'buflen'.\n *\n * Returns:\n *  <0 - error, stop reading.\n *   0 - end of response\n *  >0 - number of bytes read into buffer.\n */\nssize_t ne_read_response_block(ne_request *req, char *buffer, size_t buflen);\n\n/* Read response blocks until end of response; exactly equivalent to\n * calling ne_read_response_block() until it returns 0.  Returns\n * non-zero on error. */\nint ne_discard_response(ne_request *req);\n\n/* Read response blocks until end of response, writing content to the\n * given file descriptor.  Returns NE_ERROR on error. */\nint ne_read_response_to_fd(ne_request *req, int fd)\n    ne_attribute((nonnull));\n\n/* Read response blocks until the end of the response, writing content\n * to the buffer of length *buflen. On success, *buflen is updated\n * with the number of bytes read. If the buffer is too small to\n * contain the response, NE_FAILED is returned. */\nint ne_read_response_to_buffer(ne_request *req, char *buf, size_t *buflen)\n    ne_attribute((nonnull));\n\n/* Defined request flags: */\ntypedef enum ne_request_flag_e {\n    NE_REQFLAG_EXPECT100 = 0, /* enable this flag to enable use of the\n                               * \"Expect: 100-continue\" for the\n                               * request. */\n\n    NE_REQFLAG_IDEMPOTENT, /* disable this flag if the request uses a\n                            * non-idempotent method such as POST. */\n\n    NE_REQFLAG_1XXTIMEOUT, /* disable this flag to apply no overall\n                             * timeout when reading interim\n                             * responses. */\n\n    NE_REQFLAG_LAST /* enum sentinel value */\n} ne_request_flag;\n\n/* Set a new value for a particular request flag. */\nvoid ne_set_request_flag(ne_request *req, ne_request_flag flag, int value);\n\n/* Return 0 if the given flag is not set, >0 it is set, or -1 if the\n * flag is not supported. */\nint ne_get_request_flag(ne_request *req, ne_request_flag flag);\n\n/* Callback to handle an interim (1xx) response. The status-code of\n * the response is passed as 'status'; interim response headers can be\n * accessed via ne_get_response_header. */\ntypedef void (*ne_interim_response_fn)(void *userdata, ne_request *req,\n                                       const ne_status *status);\n\n/* Add a interim response callback handler for the request. */\nvoid ne_add_interim_handler(ne_request *req, ne_interim_response_fn fn,\n                            void *userdata);\n\n/**** Request hooks handling *****/\n\n/* Hook called when a request is created; passed the method and\n * request-target as used in the request-line (RFC 9112§3.2).  The\n * create_request hook is called exactly once per request. */\ntypedef void (*ne_create_request_fn)(ne_request *req, void *userdata,\n\t\t\t\t     const char *method, const char *target);\nvoid ne_hook_create_request(ne_session *sess, \n\t\t\t    ne_create_request_fn fn, void *userdata);\n\n/* Hook called before the request is sent.  'header' is the raw HTTP\n * header before the trailing CRLF is added; more headers can be added\n * here.  A pre_send hook may be called >1 time per request if the\n * request is retried due to a post_send hook returning NE_RETRY. */\ntypedef void (*ne_pre_send_fn)(ne_request *req, void *userdata, \n\t\t\t       ne_buffer *header);\nvoid ne_hook_pre_send(ne_session *sess, ne_pre_send_fn fn, void *userdata);\n\n/* Hook called directly after the response headers have been read, but\n * before the resposnse body has been read.  'status' is the response\n * status-code.  A post_header hook may be called >1 time per request\n * if the request is retried due to a post_send hook returning\n * NE_RETRY. */\ntypedef void (*ne_post_headers_fn)(ne_request *req, void *userdata,\n                                   const ne_status *status);\nvoid ne_hook_post_headers(ne_session *sess, \n                          ne_post_headers_fn fn, void *userdata);\n\n/* Hook called after the request is dispatched (request sent, and\n * the entire response read).  If an error occurred reading the response,\n * this hook will not run.  May return:\n *  NE_OK     everything is okay\n *  NE_RETRY  try sending the request again.\n * anything else signifies an error, and the request is failed. The return\n * code is passed back the _dispatch caller, so the session error must\n * also be set appropriately (ne_set_error).\n */\ntypedef int (*ne_post_send_fn)(ne_request *req, void *userdata,\n\t\t\t       const ne_status *status);\nvoid ne_hook_post_send(ne_session *sess, ne_post_send_fn fn, void *userdata);\n\n/* Hook called when the function is destroyed. */\ntypedef void (*ne_destroy_req_fn)(ne_request *req, void *userdata);\nvoid ne_hook_destroy_request(ne_session *sess,\n\t\t\t     ne_destroy_req_fn fn, void *userdata);\n\ntypedef void (*ne_destroy_sess_fn)(void *userdata);\n/* Hook called when the session is about to be destroyed. */\nvoid ne_hook_destroy_session(ne_session *sess,\n\t\t\t     ne_destroy_sess_fn fn, void *userdata);\n\ntypedef void (*ne_close_conn_fn)(void *userdata);\n/* Hook called when the connection is closed; note that this hook\n * may be called *AFTER* the destroy_session hook. */\nvoid ne_hook_close_conn(ne_session *sess, ne_close_conn_fn fn, void *userdata);\n\n/* The ne_unhook_* functions remove a hook registered with the given\n * session.  If a hook is found which was registered with a given\n * function 'fn', and userdata pointer 'userdata', then it will be\n * removed from the hooks list.\n *\n * It is unsafe to use any of these functions from a hook function to\n * unregister itself, except for ne_unhook_destroy_request. */\nvoid ne_unhook_create_request(ne_session *sess, \n                              ne_create_request_fn fn, void *userdata);\nvoid ne_unhook_pre_send(ne_session *sess, ne_pre_send_fn fn, void *userdata);\nvoid ne_unhook_post_headers(ne_session *sess, ne_post_headers_fn fn, void *userdata);\nvoid ne_unhook_post_send(ne_session *sess, ne_post_send_fn fn, void *userdata);\nvoid ne_unhook_destroy_request(ne_session *sess,\n                               ne_destroy_req_fn fn, void *userdata);\nvoid ne_unhook_destroy_session(ne_session *sess,\n                               ne_destroy_sess_fn fn, void *userdata);\nvoid ne_unhook_close_conn(ne_session *sess, \n                          ne_close_conn_fn fn, void *userdata);\n\n/* Store an opaque context for the request, 'priv' is returned by a\n * call to ne_request_get_private with the same ID. */\nvoid ne_set_request_private(ne_request *req, const char *id, void *priv);\nvoid *ne_get_request_private(ne_request *req, const char *id);\n\nNE_END_DECLS\n\n#endif /* NE_REQUEST_H */\n"
  },
  {
    "path": "src/ne_session.c",
    "content": "/* \n   HTTP session handling\n   Copyright (C) 1999-2021, Joe Orton <joe@manyfish.co.uk>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n   \n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n\n#include \"config.h\"\n\n#ifdef HAVE_STRING_H\n#include <string.h>\n#endif\n#ifdef HAVE_STDLIB_H\n#include <stdlib.h>\n#endif\n#ifdef HAVE_ERRNO_H\n#include <errno.h>\n#endif\n\n#ifdef HAVE_LIBPROXY\n#include <proxy.h>\n#endif\n\n#include \"ne_session.h\"\n#include \"ne_alloc.h\"\n#include \"ne_utils.h\"\n#include \"ne_internal.h\"\n#include \"ne_string.h\"\n#include \"ne_dates.h\"\n\n#include \"ne_private.h\"\n\n/* Destroy a a list of hooks. */\nstatic void destroy_hooks(struct hook *hooks)\n{\n    struct hook *nexthk;\n\n    while (hooks) {\n\tnexthk = hooks->next;\n\tne_free(hooks);\n\thooks = nexthk;\n    }\n}\n\nstatic void free_hostinfo(struct host_info *hi)\n{\n    if (hi->hostname) ne_free(hi->hostname);\n    if (hi->hostport) ne_free(hi->hostport);\n    if (hi->address) ne_addr_destroy(hi->address);\n    if (hi->literal) ne_iaddr_free(hi->literal);\n}\n\n/* Destroy the sess->proxies array. */\nstatic void free_proxies(ne_session *sess)\n{\n    struct host_info *hi, *nexthi;\n\n    for (hi = sess->proxies; hi; hi = nexthi) {\n        nexthi = hi->next;\n        free_hostinfo(hi);\n        ne_free(hi);\n    }\n\n    sess->proxies = NULL;\n    sess->any_proxy_http = 0;\n}\n\nvoid ne_session_destroy(ne_session *sess) \n{\n    struct hook *hk;\n\n    NE_DEBUG(NE_DBG_HTTP, \"sess: Destroying session (connected=%d).\\n\",\n             sess->connected);\n\n    /* Run the destroy hooks. */\n    for (hk = sess->destroy_sess_hooks; hk != NULL; hk = hk->next) {\n\tne_destroy_sess_fn fn = (ne_destroy_sess_fn)hk->fn;\n\tfn(hk->userdata);\n    }\n\n    /* Close the connection; note that the notifier callback could\n     * still be invoked here. */\n    if (sess->connected) {\n        ne_close_connection(sess);\n    }\n    \n    destroy_hooks(sess->create_req_hooks);\n    destroy_hooks(sess->pre_send_hooks);\n    destroy_hooks(sess->post_headers_hooks);\n    destroy_hooks(sess->post_send_hooks);\n    destroy_hooks(sess->destroy_req_hooks);\n    destroy_hooks(sess->destroy_sess_hooks);\n    destroy_hooks(sess->close_conn_hooks);\n    destroy_hooks(sess->private);\n\n    ne_free(sess->scheme);\n\n    free_hostinfo(&sess->server);\n    free_proxies(sess);\n\n    if (sess->user_agent) ne_free(sess->user_agent);\n    if (sess->socks_user) ne_free(sess->socks_user);\n    if (sess->socks_password) ne_free(sess->socks_password);\n\n#ifdef NE_HAVE_SSL\n    if (sess->ssl_context)\n        ne_ssl_context_destroy(sess->ssl_context);\n\n    if (sess->server_cert)\n        ne_ssl_cert_free(sess->server_cert);\n#endif\n\n    ne_free(sess);\n}\n\nint ne_version_pre_http11(ne_session *s)\n{\n    return !s->is_http11;\n}\n\n/* Stores the \"hostname[:port]\" segment */\nstatic void set_hostport(struct host_info *host, unsigned int defaultport)\n{\n    if (host->port == defaultport) {\n        host->hostport = ne_strdup(host->hostname);\n    }\n    else {\n        char buf[512];\n\n        ne_snprintf(buf, sizeof buf, \"%s:%u\", host->hostname, host->port);\n        host->hostport = ne_strdup(buf);\n    }\n}\n\n#define V6_ADDR_MINLEN strlen(\"[::1]\") /* \"[::]\" never valid */\n#define V6_SCOPE_SEP \"%25\"\n#define V6_SCOPE_SEPLEN (strlen(V6_SCOPE_SEP))\n/* Minimum length of link-local address with scope. */\n#define V6_SCOPE_MINLEN (strlen(\"[fe80::%251]\"))\n\n/* Stores the hostname/port in *HI, setting up the \"hostport\" segment\n * correctly. RFC 6874 syntax is allowed here but the scope ID is\n * stripped from the hostname which is used in the Host header.  RFC\n * 9110's Host header uses uri-host, which references RFC 3986 and not\n * RFC 6874, so it is pedantically correct; the scope ID also has no\n * possible interpretation outside of the client host.\n *\n * TODO: This function also does not propagate parse failures or scope\n * mapping failures, which is bad. */\nstatic void set_hostinfo(struct host_info *hi, enum proxy_type type, \n                         const char *hostname, unsigned int port)\n{\n    ne_inet_addr *ia;\n    size_t hlen;\n\n    hi->hostname = ne_strdup(hostname);\n    hi->port = port;\n    hi->proxy = type;\n\n    hlen = strlen(hi->hostname);\n\n    /* IP literal parsing. */\n    ia = ne_iaddr_parse(hi->hostname, ne_iaddr_ipv4);\n    if (!ia && hlen >= V6_ADDR_MINLEN\n        && hi->hostname[0] == '[' && hi->hostname[hlen-1] == ']') {\n        const char *v6end;\n        char *v6start = hi->hostname + 1, *scope = NULL, *v6lit;\n\n        /* Parse here, see if there is a Zone ID:\n         *  IPv6addrzb => v6start = IPv6address \"%25\" ZoneID */\n\n        if (hlen >= V6_SCOPE_MINLEN\n            && (scope = strstr(v6start, V6_SCOPE_SEP)) != NULL)\n            v6end = scope;\n        else\n            v6end = hi->hostname + hlen - 1; /* trailing ']' */\n\n        /* Extract the IPv6-literal part. */\n        v6lit = ne_strndup(v6start, v6end - v6start);\n        ia = ne_iaddr_parse(v6lit, ne_iaddr_ipv6);\n        if (ia && scope) {\n            /* => scope = \"%25\" scope  \"]\" */\n            char *v6scope = ne_strndup(scope + V6_SCOPE_SEPLEN,\n                                       strlen(scope) - (V6_SCOPE_SEPLEN + 1));\n\n            if (ne_iaddr_set_scope(ia, v6scope) == 0) {\n                /* Strip scope from hostname since it's used in Host:\n                 * headers and will be rejected. This is safe since\n                 * strlen(scope) is assured by strstr() above. */\n                *scope++ = ']';\n                *scope = '\\0';\n                NE_DEBUG(NE_DBG_HTTP, \"sess: Using IPv6 scope '%s', \"\n                         \"hostname rewritten to %s.\\n\", v6scope,\n                         hi->hostname);\n            }\n            else {\n                NE_DEBUG(NE_DBG_HTTP, \"sess: Failed to set IPv6 scope '%s' \"\n                         \"for address %s.\\n\", v6scope, v6lit);\n            }\n\n            ne_free(v6scope);\n        }\n\n        ne_free(v6lit);\n    }\n\n    if (ia) {\n        NE_DEBUG(NE_DBG_HTTP, \"sess: Using IP literal address for %s\\n\",\n                 hostname);\n        hi->network = hi->literal = ia;\n    }\n}\n\nne_session *ne_session_create(const char *scheme,\n\t\t\t      const char *hostname, unsigned int port)\n{\n    ne_session *sess = ne_calloc(sizeof *sess);\n\n    NE_DEBUG(NE_DBG_HTTP, \"HTTP session to %s://%s:%d begins.\\n\",\n\t     scheme, hostname, port);\n\n    ne_strnzcpy(sess->error, _(\"Unknown error.\"), sizeof sess->error);\n\n    sess->scheme = ne_strlower(ne_strdup(scheme));\n    /* use SSL if scheme is https */\n    sess->use_ssl = !strcmp(sess->scheme, \"https\");\n    \n    /* set the hostname/port */\n    set_hostinfo(&sess->server, PROXY_NONE, hostname, port);\n    set_hostport(&sess->server, sess->use_ssl?443:80);\n\n#ifdef NE_HAVE_SSL\n    if (sess->use_ssl) {\n        sess->ssl_context = ne_ssl_context_create(0);\n        \n        if (!sess->server.literal) {\n            sess->flags[NE_SESSFLAG_TLS_SNI] = 1;\n        }\n        NE_DEBUG(NE_DBG_SSL, \"ssl: SNI %s by default.\\n\",\n                 sess->flags[NE_SESSFLAG_TLS_SNI] ?\n                 \"enabled\" : \"disabled\");\n    }\n#endif\n\n    /* Set flags which default to on: */\n    sess->flags[NE_SESSFLAG_PERSIST] = 1;\n    sess->flags[NE_SESSFLAG_STRICT] = 1;\n\n#ifdef NE_ENABLE_AUTO_LIBPROXY\n    ne_session_system_proxy(sess, 0);\n#endif\n\n    return sess;\n}\n\nvoid ne_session_proxy(ne_session *sess, const char *hostname,\n\t\t      unsigned int port)\n{\n    free_proxies(sess);\n\n    sess->proxies = ne_calloc(sizeof *sess->proxies);\n\n    sess->any_proxy_http = 1;\n    \n    set_hostinfo(sess->proxies, PROXY_HTTP, hostname, port);\n}\n\nvoid ne_session_socks_proxy(ne_session *sess, enum ne_sock_sversion vers, \n                            const char *hostname, unsigned int port,\n                            const char *username, const char *password)\n{\n    free_proxies(sess);\n\n    sess->proxies = ne_calloc(sizeof *sess->proxies);\n\n    set_hostinfo(sess->proxies, PROXY_SOCKS, hostname, port);\n\n    sess->socks_ver = vers;\n\n    if (username) sess->socks_user = ne_strdup(username);\n    if (password) sess->socks_password = ne_strdup(password);\n}\n\nvoid ne_session_system_proxy(ne_session *sess, unsigned int flags)\n{\n#ifdef HAVE_LIBPROXY\n    pxProxyFactory *pxf = px_proxy_factory_new();\n    struct host_info *hi, **lasthi;\n    char *url, **proxies;\n    ne_uri uri;\n    unsigned n;\n\n    free_proxies(sess);\n\n    /* Create URI for session to pass off to libproxy */\n    memset(&uri, 0, sizeof uri);\n    ne_fill_server_uri(sess, &uri);\n\n    uri.path = \"/\"; /* make valid URI structure. */\n    url = ne_uri_unparse(&uri);\n    uri.path = NULL;\n\n    /* Get list of pseudo-URIs from libproxy: */\n    proxies = px_proxy_factory_get_proxies(pxf, url);\n    \n    for (n = 0, lasthi = &sess->proxies; proxies[n]; n++) {\n        enum proxy_type ptype;\n\n        ne_uri_free(&uri);\n\n        NE_DEBUG(NE_DBG_HTTP, \"sess: libproxy #%u=%s\\n\", \n                 n, proxies[n]);\n\n        if (ne_uri_parse(proxies[n], &uri))\n            continue;\n        \n        if (!uri.scheme) continue;\n\n        if (ne_strcasecmp(uri.scheme, \"http\") == 0)\n            ptype = PROXY_HTTP;\n        else if (ne_strcasecmp(uri.scheme, \"socks\") == 0)\n            ptype = PROXY_SOCKS;\n        else if (ne_strcasecmp(uri.scheme, \"direct\") == 0)\n            ptype = PROXY_NONE;\n        else\n            continue;\n\n        /* Hostname/port required for http/socks schemes. */\n        if (ptype != PROXY_NONE && !(uri.host && uri.port))\n            continue;\n        \n        /* Do nothing if libproxy returned only a single \"direct://\"\n         * entry -- a single \"direct\" (noop) proxy is equivalent to\n         * having none. */\n        if (n == 0 && proxies[1] == NULL && ptype == PROXY_NONE)\n            break;\n\n        NE_DEBUG(NE_DBG_HTTP, \"sess: Got proxy %s://%s:%d\\n\",\n                 uri.scheme, uri.host ? uri.host : \"(none)\",\n                 uri.port);\n        \n        hi = *lasthi = ne_calloc(sizeof *hi);\n        \n        if (ptype == PROXY_NONE) {\n            /* A \"direct\" URI requires an attempt to connect directly to\n             * the origin server, so dup the server details. */\n            set_hostinfo(hi, ptype, sess->server.hostname,\n                         sess->server.port);\n        }\n        else {\n            /* SOCKS/HTTP proxy. */\n            set_hostinfo(hi, ptype, uri.host, uri.port);\n\n            if (ptype == PROXY_HTTP)\n                sess->any_proxy_http = 1;\n            else if (ptype == PROXY_SOCKS)\n                sess->socks_ver = NE_SOCK_SOCKSV5;\n        }\n\n        lasthi = &hi->next;\n    }\n\n    /* Free up the proxies array: */\n    for (n = 0; proxies[n]; n++)\n        free(proxies[n]);\n    free(proxies[n]);\n\n    ne_free(url);\n    ne_uri_free(&uri);\n    px_proxy_factory_free(pxf);\n#endif\n}\n\nvoid ne_set_addrlist2(ne_session *sess, unsigned int port,\n                      const ne_inet_addr **addrs, size_t n)\n{\n    struct host_info *hi, **lasthi;\n    size_t i;\n\n    free_proxies(sess);\n\n    lasthi = &sess->proxies;\n\n    for (i = 0; i < n; i++) {\n        *lasthi = hi = ne_calloc(sizeof *hi);\n        \n        hi->proxy = PROXY_NONE;\n        hi->network = addrs[i];\n        hi->port = port;\n\n        lasthi = &hi->next;\n    }\n}\n\nvoid ne_set_addrlist(ne_session *sess, const ne_inet_addr **addrs, size_t n)\n{\n    ne_set_addrlist2(sess, sess->server.port, addrs, n);\n}\n\nvoid ne_set_localaddr(ne_session *sess, const ne_inet_addr *addr)\n{\n    sess->local_addr = addr;    \n}\n\nvoid ne_set_error(ne_session *sess, const char *format, ...)\n{\n    va_list params;\n\n    va_start(params, format);\n    ne_vsnprintf(sess->error, sizeof sess->error, format, params);\n    va_end(params);\n}\n\nvoid ne_set_session_flag(ne_session *sess, ne_session_flag flag, int value)\n{\n    if (flag < NE_SESSFLAG_LAST) {\n        sess->flags[flag] = value;\n    }\n}\n\nint ne_get_session_flag(ne_session *sess, ne_session_flag flag)\n{\n    if (flag < NE_SESSFLAG_LAST) {\n        return sess->flags[flag];\n    }\n    return -1;\n}\n\nstatic void progress_notifier(void *userdata, ne_session_status status,\n                              const ne_session_status_info *info)\n{\n    ne_session *sess = userdata;\n\n    if (status == ne_status_sending || status == ne_status_recving) {\n        sess->progress_cb(sess->progress_ud, info->sr.progress, info->sr.total);    \n    }\n}\n\nvoid ne_set_progress(ne_session *sess, ne_progress progress, void *userdata)\n{\n    if (progress) {\n        sess->progress_cb = progress;\n        sess->progress_ud = userdata;\n        ne_set_notifier(sess, progress_notifier, sess);\n    }\n    else {\n        ne_set_notifier(sess, NULL, NULL);\n    }\n}\n\nvoid ne_set_notifier(ne_session *sess,\n\t\t     ne_notify_status status, void *userdata)\n{\n    sess->notify_cb = status;\n    sess->notify_ud = userdata;\n}\n\nvoid ne_set_read_timeout(ne_session *sess, int timeout)\n{\n    sess->rdtimeout = timeout;\n}\n\nvoid ne_set_connect_timeout(ne_session *sess, int timeout)\n{\n    sess->cotimeout = timeout;\n}\n\n#define UAHDR \"User-Agent: \"\n#define AGENT \" neon/\" NEON_VERSION \"\\r\\n\"\n\nvoid ne_set_useragent(ne_session *sess, const char *token)\n{\n    if (sess->user_agent) ne_free(sess->user_agent);\n    sess->user_agent = ne_concat(UAHDR, token, AGENT, NULL);\n}\n\nconst char *ne_get_server_hostport(ne_session *sess)\n{\n    return sess->server.hostport;\n}\n\nconst char *ne_get_scheme(ne_session *sess)\n{\n    return sess->scheme;\n}\n\nvoid ne_fill_server_uri(ne_session *sess, ne_uri *uri)\n{\n    uri->host = ne_strdup(sess->server.hostname);\n    uri->port = sess->server.port;\n    uri->scheme = ne_strdup(sess->scheme);\n}\n\nvoid ne_fill_proxy_uri(ne_session *sess, ne_uri *uri)\n{\n    if (sess->proxies) {\n        const struct host_info *hi = sess->nexthop ? sess->nexthop : sess->proxies;\n\n        if (hi->proxy == PROXY_HTTP) {\n            uri->host = ne_strdup(hi->hostname);\n            uri->port = hi->port;\n        }\n    }\n}\n\nconst char *ne_get_error(ne_session *sess)\n{\n    return sess->error;\n}\n\nvoid ne_close_connection(ne_session *sess)\n{\n    if (sess->connected) {\n        struct hook *hk;\n\n        NE_DEBUG(NE_DBG_SOCKET, \"sess: Closing connection.\\n\");\n\n        if (sess->notify_cb) {\n            sess->status.cd.hostname = sess->nexthop->hostname;\n            sess->notify_cb(sess->notify_ud, ne_status_disconnected, \n                            &sess->status);\n        }\n\n        /* Run the close_conn hooks. */\n        for (hk = sess->close_conn_hooks; hk != NULL; hk = hk->next) {\n            ne_close_conn_fn fn = (ne_close_conn_fn)hk->fn;\n            fn(hk->userdata);\n        }\n\n\tne_sock_close(sess->socket);\n\tsess->socket = NULL;\n        NE_DEBUG(NE_DBG_SOCKET, \"sess: Connection closed.\\n\");\n    } else {\n        NE_DEBUG(NE_DBG_SOCKET, \"sess: Not closing closed connection.\\n\");\n    }\n    sess->connected = 0;\n}\n\nvoid ne_ssl_set_verify(ne_session *sess, ne_ssl_verify_fn fn, void *userdata)\n{\n    sess->ssl_verify_fn = fn;\n    sess->ssl_verify_ud = userdata;\n}\n\n#ifdef NE_HAVE_SSL\nstatic void sess_ccprovider(void *userdata, const ne_ssl_dname *const *dnames,\n                            int dncount)\n{\n    ne_session *sess = userdata;\n\n    sess->ssl_provide_fn(sess->ssl_provide_ud, sess,\n                         dnames, dncount);\n}\n#endif\n\nvoid ne_ssl_provide_clicert(ne_session *sess,\n                            ne_ssl_provide_fn fn, void *userdata)\n{\n#ifdef NE_HAVE_SSL\n    if (sess->ssl_context) {\n        sess->ssl_provide_fn = fn;\n        sess->ssl_provide_ud = userdata;\n\n        ne_ssl_context_set_ccprovide(sess->ssl_context,\n                                     sess_ccprovider, sess);\n    }\n#endif\n}\n\nvoid ne_ssl_set_clicert(ne_session *sess, const ne_ssl_client_cert *cc)\n{\n#ifdef NE_HAVE_SSL\n    if (sess->ssl_context)\n        ne_ssl_context_set_clicert(sess->ssl_context, cc);\n#endif\n}\n\nvoid ne_ssl_trust_cert(ne_session *sess, const ne_ssl_certificate *cert)\n{\n#ifdef NE_HAVE_SSL\n    if (sess->ssl_context) {\n        ne_ssl_context_trustcert(sess->ssl_context, cert);\n    }\n#endif\n}\n\nvoid ne_ssl_trust_default_ca(ne_session *sess)\n{\n#ifdef NE_HAVE_SSL\n    if (sess->ssl_context)\n        ne_ssl_context_trustdefca(sess->ssl_context);\n#endif\n}\n\nint ne_ssl_set_protovers(ne_session *sess, enum ne_ssl_protocol min,\n                         enum ne_ssl_protocol max)\n{\n#ifdef NE_HAVE_SSL\n    if (sess->ssl_context) {\n        if (ne_ssl_context_set_versions(sess->ssl_context, min, max) != 0) {\n            ne_set_error(sess, _(\"Could not set minimum/maximum SSL/TLS versions\"));\n            return NE_ERROR;\n        }\n\n        return NE_OK;\n    }\n#endif\n    ne_set_error(sess, _(\"SSL/TLS not enabled for the session\"));\n    return NE_ERROR;\n}\n\nstatic const char *const ssl_proto_names[] = { \"unknown\", \"SSLv3\",\n                                               \"TLSv1.0\", \"TLSv1.1\",\n                                               \"TLSv1.2\", \"TLSv1.3\" };\n\nconst char *ne_ssl_proto_name(enum ne_ssl_protocol proto)\n{\n    if (proto < (sizeof(ssl_proto_names)/sizeof(ssl_proto_names[0])))\n        return ssl_proto_names[proto];\n    else\n        return ssl_proto_names[0];\n}\n\nvoid ne_ssl_cert_validity(const ne_ssl_certificate *cert, char *from, char *until)\n{\n#ifdef NE_HAVE_SSL\n    time_t tf, tu;\n    char *date;\n\n    ne_ssl_cert_validity_time(cert, &tf, &tu);\n    \n    if (from) {\n        if (tf != (time_t) -1) {\n            date = ne_rfc1123_date(tf);\n            ne_strnzcpy(from, date, NE_SSL_VDATELEN);\n            ne_free(date);\n        }\n        else {\n            ne_strnzcpy(from, _(\"[invalid date]\"), NE_SSL_VDATELEN);\n        }\n    }\n        \n    if (until) {\n        if (tu != (time_t) -1) {\n            date = ne_rfc1123_date(tu);\n            ne_strnzcpy(until, date, NE_SSL_VDATELEN);\n            ne_free(date);\n        }\n        else {\n            ne_strnzcpy(until, _(\"[invalid date]\"), NE_SSL_VDATELEN);\n        }\n    }\n#endif\n}\n\n#ifdef NE_HAVE_SSL\nstatic int check_certificate(ne_session *sess, ne_ssl_certificate *cert)\n{\n    int failures = 0;\n    const char *hostname = sess->server.literal ? NULL : sess->server.hostname;\n\n    if (sess->server_cert && ne_ssl_cert_cmp(cert, sess->server_cert) == 0) {\n        /* Same leaf cert used as last time - no need to reverify. */\n        ne_ssl_cert_free(cert);\n        return NE_OK;\n    }\n\n    if (ne_ssl_check_certificate(sess->ssl_context, sess->socket,\n                                 hostname, sess->server.literal,\n                                 cert, 0, &failures)) {\n        /* Propagate error back. */\n        ne_set_error(sess, _(\"SSL error: %s\"), ne_sock_error(sess->socket));\n        /* Fail, or allow override for non-fatal errors (failures!=0). */\n        if (!failures || !sess->ssl_verify_fn\n            || sess->ssl_verify_fn(sess->ssl_verify_ud, failures, cert)) {\n            ne_ssl_cert_free(cert);\n            return NE_ERROR;\n        }\n    }\n\n    sess->server_cert = cert;\n    return NE_OK;\n}\n\n/* For internal use only. */\nint ne__negotiate_ssl(ne_session *sess)\n{\n    ne_ssl_context *ctx = sess->ssl_context;\n    ne_ssl_certificate *cert;\n    const char *snihost;\n\n    NE_DEBUG(NE_DBG_SSL, \"sess: Doing SSL negotiation.\\n\");\n\n    /* Pass through the hostname if SNI is enabled. */\n    snihost = sess->flags[NE_SESSFLAG_TLS_SNI] ? sess->server.hostname : NULL;\n\n    if (ne_sock_handshake(sess->socket, ctx, snihost, 0)) {\n        ne_set_error(sess, _(\"SSL handshake failed: %s\"),\n                     ne_sock_error(sess->socket));\n        return NE_ERROR;\n    }\n\n    cert = ne_sock_getcert(sess->socket, sess->ssl_context);\n    if (!cert) {\n        ne_set_error(sess, _(\"No server certificate: %s\"),\n                     ne_sock_error(sess->socket));\n        return NE_ERROR;\n    }\n\n    if (check_certificate(sess, cert)) {\n        return NE_ERROR;\n    }\n\n    if (sess->notify_cb) {\n        char *ciph = ne_sock_cipher(sess->socket);\n\n        sess->status.hs.protocol = ne_sock_getproto(sess->socket);\n        sess->status.hs.ciphersuite = ciph;\n        sess->notify_cb(sess->notify_ud, ne_status_handshake, &sess->status);\n        if (ciph) ne_free(ciph);\n    }\n\n    return NE_OK;\n}\n#endif /* NE_HAVE_SSL */\n\ntypedef void (*void_fn)(void);\n\n#define ADD_HOOK(hooks, fn, ud) add_hook(&(hooks), NULL, (void_fn)(fn), (ud))\n\nstatic void add_hook(struct hook **hooks, const char *id, void_fn fn, void *ud)\n{\n    struct hook *hk = ne_malloc(sizeof (struct hook)), *pos;\n\n    if (*hooks != NULL) {\n\tfor (pos = *hooks; pos->next != NULL; pos = pos->next)\n\t    /* nullop */;\n\tpos->next = hk;\n    } else {\n\t*hooks = hk;\n    }\n\n    hk->id = id;\n    hk->fn = fn;\n    hk->userdata = ud;\n    hk->next = NULL;\n}\n\nvoid ne_hook_create_request(ne_session *sess, \n\t\t\t    ne_create_request_fn fn, void *userdata)\n{\n    ADD_HOOK(sess->create_req_hooks, fn, userdata);\n}\n\nvoid ne_hook_pre_send(ne_session *sess, ne_pre_send_fn fn, void *userdata)\n{\n    ADD_HOOK(sess->pre_send_hooks, fn, userdata);\n}\n\nvoid ne_hook_post_send(ne_session *sess, ne_post_send_fn fn, void *userdata)\n{\n    ADD_HOOK(sess->post_send_hooks, fn, userdata);\n}\n\nvoid ne_hook_post_headers(ne_session *sess, ne_post_headers_fn fn, \n                          void *userdata)\n{\n    ADD_HOOK(sess->post_headers_hooks, fn, userdata);\n}\n\nvoid ne_hook_destroy_request(ne_session *sess,\n\t\t\t     ne_destroy_req_fn fn, void *userdata)\n{\n    ADD_HOOK(sess->destroy_req_hooks, fn, userdata);    \n}\n\nvoid ne_hook_destroy_session(ne_session *sess,\n\t\t\t     ne_destroy_sess_fn fn, void *userdata)\n{\n    ADD_HOOK(sess->destroy_sess_hooks, fn, userdata);\n}\n\nvoid ne_hook_close_conn(ne_session *sess,\n                        ne_close_conn_fn fn, void *userdata)\n{\n    ADD_HOOK(sess->close_conn_hooks, fn, userdata);\n}\n\nvoid ne_set_session_private(ne_session *sess, const char *id, void *userdata)\n{\n    add_hook(&sess->private, id, NULL, userdata);\n}\n\nstatic void remove_hook(struct hook **hooks, void_fn fn, void *ud)\n{\n    struct hook **p = hooks;\n\n    while (*p) {\n        if ((*p)->fn == fn && (*p)->userdata == ud) {\n            struct hook *next = (*p)->next;\n            ne_free(*p);\n            (*p) = next;\n            break;\n        }\n        p = &(*p)->next;\n    }\n}\n\n#define REMOVE_HOOK(hooks, fn, ud) remove_hook(&hooks, (void_fn)fn, ud)\n\nvoid ne_unhook_create_request(ne_session *sess, \n                              ne_create_request_fn fn, void *userdata)\n{\n    REMOVE_HOOK(sess->create_req_hooks, fn, userdata);\n}\n\nvoid ne_unhook_pre_send(ne_session *sess, ne_pre_send_fn fn, void *userdata)\n{\n    REMOVE_HOOK(sess->pre_send_hooks, fn, userdata);\n}\n\nvoid ne_unhook_post_headers(ne_session *sess, ne_post_headers_fn fn, \n\t\t\t    void *userdata)\n{\n    REMOVE_HOOK(sess->post_headers_hooks, fn, userdata);\n}\n\nvoid ne_unhook_post_send(ne_session *sess, ne_post_send_fn fn, void *userdata)\n{\n    REMOVE_HOOK(sess->post_send_hooks, fn, userdata);\n}\n\nvoid ne_unhook_destroy_request(ne_session *sess,\n                               ne_destroy_req_fn fn, void *userdata)\n{\n    REMOVE_HOOK(sess->destroy_req_hooks, fn, userdata);    \n}\n\nvoid ne_unhook_destroy_session(ne_session *sess,\n                               ne_destroy_sess_fn fn, void *userdata)\n{\n    REMOVE_HOOK(sess->destroy_sess_hooks, fn, userdata);\n}\n\nvoid ne_unhook_close_conn(ne_session *sess,\n                          ne_close_conn_fn fn, void *userdata)\n{\n    REMOVE_HOOK(sess->close_conn_hooks, fn, userdata);\n}\n"
  },
  {
    "path": "src/ne_session.h",
    "content": "/* \n   HTTP session handling\n   Copyright (C) 1999-2021, Joe Orton <joe@manyfish.co.uk>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n   \n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n\n#ifndef NE_SESSION_H\n#define NE_SESSION_H 1\n\n#include <sys/types.h>\n\n#include \"ne_ssl.h\"\n#include \"ne_uri.h\" /* for ne_uri */\n#include \"ne_defs.h\"\n#include \"ne_socket.h\"\n\nNE_BEGIN_DECLS\n\ntypedef struct ne_session_s ne_session;\n\n/* Create a session to the server 'host', using the given scheme.  If\n * \"https\" is passed as the scheme, TLS will be used to connect to the\n * server. The host string must follow the definition of 'host' in RFC\n * 3986, which can be an IP-literal or registered (DNS) hostname. An\n * IPv6 literal address must be enclosed in square brackets (for\n * example \"[::1]\"). The RFC 6874 syntax for IPv6 link-local literal\n * addresses is also supported, for example \"[fe80::1%25eth0]\". */\nne_session *ne_session_create(const char *scheme, const char *host,\n                              unsigned int port);\n\n/* Finish an HTTP session, freeing associated memory. */\nvoid ne_session_destroy(ne_session *sess);\n\n/* Prematurely force the connection to be closed for the given\n * session. */\nvoid ne_close_connection(ne_session *sess);\n\n/* Configure an HTTP proxy server for the session.  This function will\n * override (remove) any proxy servers previously configured, and must\n * be called before any requests are created using this session. */\nvoid ne_session_proxy(ne_session *sess,\n\t\t      const char *hostname, unsigned int port);\n\n/* Configure a SOCKS proxy server which will be used for the session.\n * The SOCKS protocol version 'vers' will be used to contact the\n * proxy at given 'hostname' and 'port'.\n *\n * If SOCKSv4 or v4a are used, username must be non-NULL.  For v5,\n * username may be NULL, in which case, password is ignored.  If\n * username is non-NULL, password must also be non-NULL.\n *\n * This function will override (remove) any proxy servers previously\n * configured, and must be called before any requests are created\n * using this session. */\nvoid ne_session_socks_proxy(ne_session *sess, enum ne_sock_sversion vers,\n                            const char *hostname, unsigned int port,\n                            const char *username, const char *password);\n\n/* Configure use of proxy servers from any system-wide default sources\n * which are configured at build time.  This function will override\n * (remove) any proxy servers previously configured, and must be\n * called before any requests are created using this session.  The\n * 'flags' parameter must be zero.  */\nvoid ne_session_system_proxy(ne_session *sess, unsigned int flags);\n\n/* Defined session flags: */\ntypedef enum ne_session_flag_e {\n    NE_SESSFLAG_PERSIST = 0, /* disable this flag to prevent use of\n                              * persistent connections. */\n\n    NE_SESSFLAG_ICYPROTO, /* enable this flag to enable support for\n                           * non-HTTP ShoutCast-style \"ICY\" responses. */\n\n    NE_SESSFLAG_SSLv2, /* this flag is ignored */\n\n    NE_SESSFLAG_RFC4918, /* enable this flag to enable support for\n                          * RFC4918-only WebDAV features; losing\n                          * backwards-compatibility with RFC2518\n                          * servers. */\n\n    NE_SESSFLAG_CONNAUTH, /* enable this flag if an awful, broken,\n                           * RFC-violating, connection-based HTTP\n                           * authentication scheme is in use. */\n\n    NE_SESSFLAG_TLS_SNI, /* disable this flag to disable use of the\n                          * TLS Server Name Indication extension. */\n\n    NE_SESSFLAG_EXPECT100, /* enable this flag to enable the flag\n                            * NE_REQFLAG_EXPECT100 for new requests. */\n\n    NE_SESSFLAG_SHAREPOINT, /* this flag enables various workarounds\n                             * to improve interoperability with\n                             * SharePoint */\n\n    NE_SESSFLAG_STRICT, /* disable this flag to parse HTTP/1.1\n                         * messages without strict requirements\n                         * introduced in RFC 7230 and later. */\n\n    NE_SESSFLAG_LAST /* enum sentinel value */\n} ne_session_flag;\n\n/* Set a new value for a particular session flag. */\nvoid ne_set_session_flag(ne_session *sess, ne_session_flag flag, int value);\n\n/* Return 0 if the given flag is not set, >0 it is set, or -1 if the\n * flag is not supported. */\nint ne_get_session_flag(ne_session *sess, ne_session_flag flag);\n\n/* Bypass the normal name resolution; force the use of specific set of\n * addresses for this session, addrs[0]...addrs[n-1].  The 'addrs'\n * array and pointed-to objects must remain valid until the session is\n * destroyed.  This function will override (remove) any proxy servers\n * previously configured, and must be called before any requests are\n * created using this session.  */\nvoid ne_set_addrlist(ne_session *sess, const ne_inet_addr **addrs, size_t n);\n\n/* Bypass the normal name resolution; force the use of specific set of\n * addresses for this session, addrs[0]...addrs[n-1].  The 'addrs'\n * array and pointed-to objects must remain valid until the session is\n * destroyed.  This function will override (remove) any proxy servers\n * previously configured, and must be called before any requests are\n * created using this session.  Port number 'port' will be used\n * instead of the \"real\" session port, to connect to the proxy. */\nvoid ne_set_addrlist2(ne_session *sess, unsigned int port, \n                      const ne_inet_addr **addrs, size_t n);\n\n/* Bind connections to the specified local address.  If the address\n * determined for the remote host has a different family (type) to\n * 'addr', 'addr' will be ignored.  The 'addr' object must remain\n * valid until the session is destroyed. */\nvoid ne_set_localaddr(ne_session *sess, const ne_inet_addr *addr);\n\n/* DEPRECATED: Progress callback. */\ntypedef void (*ne_progress)(void *userdata, ne_off_t progress, ne_off_t total);\n\n/* DEPRECATED API: Set a progress callback for the session; this is\n * deprecated in favour of ne_set_notifier().  The progress callback\n * is invoked for after each block of the request and response body to\n * indicate request and response progress (there is no way to\n * distinguish between the two using this interface alone).\n * If progress is NULL, any existing callback is deregistered and will\n * no longer be invoked.\n *\n * NOTE: Use of this interface is mutually exclusive with the use of\n * ne_set_notifier().  A call to ne_set_progress() removes the\n * notifier callback, and vice versa. */\nvoid ne_set_progress(ne_session *sess, ne_progress progress, void *userdata);\n\n/* Store an opaque context for the session, 'priv' is returned by a\n * call to ne_session_get_private with the same ID. */\nvoid ne_set_session_private(ne_session *sess, const char *id, void *priv);\nvoid *ne_get_session_private(ne_session *sess, const char *id);\n\n/* Status event type.  NOTE: More event types may be added in\n * subsequent releases, so callers must ignore unknown status types\n * for forwards-compatibility.  */\ntypedef enum {\n    ne_status_lookup = 0, /* looking up hostname */\n    ne_status_connecting, /* connecting to host */\n    ne_status_connected, /* connected to host */\n    ne_status_sending, /* sending a request body */\n    ne_status_recving, /* receiving a response body */\n    ne_status_disconnected, /* disconnected from host */\n    ne_status_handshake /* TLS handshake complete */\n} ne_session_status;\n\n/* Status event information union; the relevant structure within\n * corresponds to the event type.  WARNING: the size of this union is\n * not limited by ABI constraint; it may be extended with additional\n * members of different size, or existing members may be extended. */\ntypedef union ne_session_status_info_u {\n    struct /* ne_status_lookup */ {\n        /* The hostname which is being resolved: */\n        const char *hostname;\n    } lu;\n    struct /* ne_status_connecting */ {\n        /* The hostname and network address to which a connection\n         * attempt is being made, hostname may be NULL: */\n        const char *hostname;\n        const ne_inet_addr *address;\n    } ci;\n    struct /* ne_status_connected, ne_status_disconnected */ {\n        /* The hostname to which a connection has just been\n         * established or closed - may be NULL: */\n        const char *hostname;\n    } cd;\n    struct /* ne_status_sending and ne_status_recving */ {\n        /* Request/response body transfer progress; if total == -1,\n         * the total size is unknown; otherwise, total gives the total\n         * number of bytes which will be transferred.  progress gives\n         * the number of bytes transferred so far. */\n        ne_off_t progress, total;\n    } sr;\n    struct /* ne_status_handshake */ {\n        /* TLS handshake completed successfully; ciphersuite is\n         * non-NULL if available. */\n        enum ne_ssl_protocol protocol;\n        const char *ciphersuite;\n    } hs;\n} ne_session_status_info;\n\n/* Callback invoked to notify a new session status event, given by the\n * 'status' argument.  On invocation, the contents of exactly one of\n * the structures in the info union will be valid, as indicated\n * above. */\ntypedef void (*ne_notify_status)(void *userdata, ne_session_status status,\n                                 const ne_session_status_info *info);\n\n/* Set a status notification callback for the session, to report\n * session status events.  Only one notification callback per session\n * can be registered; the most recent of successive calls to this\n * function takes effect.  If status is NULL, any existing callback\n * is deregistered and will no longer be invoked.\n *\n * NOTE: Use of this interface is mutually exclusive with the use of\n * ne_set_progress().  A call to ne_set_notifier() removes the\n * progress callback, and vice versa. */\nvoid ne_set_notifier(ne_session *sess, ne_notify_status status, void *userdata);\n\n/* Install a callback to handle server certificate verification (see\n * ne_ssl.h for definition of ne_ssl_verify_fn).  This is required\n * when the CA certificate is not known for the server certificate, or\n * the server cert has other verification problems. */\nvoid ne_ssl_set_verify(ne_session *sess, ne_ssl_verify_fn fn, void *userdata);\n\n/* Use the given client certificate for the session.  The client cert\n * MUST be in the decrypted state, otherwise behaviour is undefined.\n * The 'clicert' object is duplicated internally so can be destroyed\n * by the caller.  */\nvoid ne_ssl_set_clicert(ne_session *sess, const ne_ssl_client_cert *clicert);\n\n/* Indicate that the certificate 'cert' is trusted; the 'cert' object\n * is duplicated internally so can be destroyed by the caller.  This\n * function has no effect for non-SSL sessions. */\nvoid ne_ssl_trust_cert(ne_session *sess, const ne_ssl_certificate *cert);\n\n/* If the SSL library provided a default set of CA certificates, trust\n * this set of CAs. This function has no effect for non-SSL\n * sessions. */\nvoid ne_ssl_trust_default_ca(ne_session *sess);\n\n/* Set the minimum and maximum SSL/TLS protocol version for the\n * session. Either minimum and/or maximum may be specified as\n * NE_SSL_PROTO_UNSPEC, in which case no limit is imposed. Returns\n * non-zero on error if the range is invalid, if the range cannot be\n * configured in the SSL/TLS toolkit, or if SSL/TLS is not in use for\n * the session. */\nint ne_ssl_set_protovers(ne_session *sess, enum ne_ssl_protocol min,\n                         enum ne_ssl_protocol max);\n\n/* Callback used to load a client certificate on demand.  If dncount\n * is > 0, the 'dnames' array dnames[0] through dnames[dncount-1]\n * gives the list of CA names which the server indicated were\n * acceptable.  The callback should load an appropriate client\n * certificate and then pass it to 'ne_ssl_set_clicert'. */\ntypedef void (*ne_ssl_provide_fn)(void *userdata, ne_session *sess,\n\t\t\t\t  const ne_ssl_dname *const *dnames,\n                                  int dncount);\n\n/* Register a function to be called when the server requests a client\n * certificate. */\nvoid ne_ssl_provide_clicert(ne_session *sess, \n                            ne_ssl_provide_fn fn, void *userdata);\n\n/* Set the timeout (in seconds) used when reading from a socket.  The\n * timeout value must be greater than zero. */\nvoid ne_set_read_timeout(ne_session *sess, int timeout);\n\n/* Set the timeout (in seconds) used when making a connection.  The\n * timeout value must be greater than zero. */\nvoid ne_set_connect_timeout(ne_session *sess, int timeout);\n\n/* Sets the user-agent string. neon/VERSION will be appended, to make\n * the full header \"User-Agent: product neon/VERSION\".\n * If this function is not called, the User-Agent header is not sent.\n * The product string must follow the RFC 7231§5.5.3 format, i.e.\n *       product         = token [\"/\" product-version]\n *       product-version = token\n * where token is an alphanumeric string. */\nvoid ne_set_useragent(ne_session *sess, const char *product);\n\n/* Returns non-zero if next-hop server does not claim compliance to\n * HTTP/1.1 or later. */\nint ne_version_pre_http11(ne_session *sess);\n\n/* Returns the 'hostport' URI segment for the end-server, e.g.\n * \"my.server.com:8080\". */\nconst char *ne_get_server_hostport(ne_session *sess);\n\n/* Returns the URL scheme being used for the current session, omitting\n * the trailing ':'; e.g. \"http\" or \"https\". */\nconst char *ne_get_scheme(ne_session *sess);\n\n/* Sets the host, scheme, and port fields of the given URI structure\n * to that of the configured server and scheme for the session; host\n * and scheme are malloc-allocated.  No other fields in the URI\n * structure are changed. */\nvoid ne_fill_server_uri(ne_session *sess, ne_uri *uri);\n\n/* If a proxy is configured, sets the host and port fields in the\n * given URI structure to that of the proxy.  If multiple proxies are\n * configured, the active is used if any, otherwise the first.  The\n * hostname is malloc-allocated.  No other fields in the URI structure\n * are changed; if no proxy is configured or a non-HTTP proxy is in\n * use, no fields are changed. */\nvoid ne_fill_proxy_uri(ne_session *sess, ne_uri *uri);\n\n/* Set the error string for the session; takes printf-like format\n * string. */\nvoid ne_set_error(ne_session *sess, const char *format, ...)\n    ne_attribute((format (printf, 2, 3)));\n\n/* Retrieve the error string for the session */\nconst char *ne_get_error(ne_session *sess);\n\nNE_END_DECLS\n\n#endif /* NE_SESSION_H */\n"
  },
  {
    "path": "src/ne_socket.c",
    "content": "/* \n   Socket handling routines\n   Copyright (C) 1998-2021, Joe Orton <joe@manyfish.co.uk>\n   Copyright (C) 2004 Aleix Conchillo Flaque <aleix@member.fsf.org>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n   \n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n*/\n\n/*\n  portions were originally under GPL in Mutt, http://www.mutt.org/\n  Relicensed under LGPL for neon, http://www.webdav.org/neon/\n*/\n\n#include \"config.h\"\n\n#include <sys/types.h>\n#ifdef HAVE_SYS_UIO_H\n#include <sys/uio.h> /* writev(2) */\n#endif\n#ifdef HAVE_SYS_TIME_H\n#include <sys/time.h>\n#endif\n#include <sys/stat.h>\n#ifdef HAVE_SYS_SOCKET_H\n#include <sys/socket.h>\n#endif\n\n#ifdef NE_USE_POLL\n#include <sys/poll.h>\n#elif defined(HAVE_SYS_SELECT_H)\n#include <sys/select.h>\n#endif\n\n#ifdef HAVE_NETINET_IN_H\n#include <netinet/in.h>\n#endif\n#ifdef HAVE_NETINET_TCP_H\n#include <netinet/tcp.h>\n#endif\n#ifdef HAVE_ARPA_INET_H\n#include <arpa/inet.h>\n#endif\n#ifdef HAVE_NETDB_H\n#include <netdb.h>\n#endif\n#ifdef HAVE_NET_IF_H\n#include <net/if.h>\n#endif\n\n#ifdef WIN32\n#include <winsock2.h>\n#include <stddef.h>\n#if (defined USE_GETADDRINFO) || (HAVE_SOCKLEN_T)\n#include <ws2tcpip.h>\n#endif\n#ifdef HAVE_WSPIAPI_H\n#include <wspiapi.h>\n#endif\n#endif\n\n#if defined(HAVE_OPENSSL) && defined(HAVE_LIMITS_H)\n#include <limits.h> /* for INT_MAX */\n#endif\n#ifdef HAVE_STRING_H\n#include <string.h>\n#endif\n#ifdef HAVE_STRINGS_H\n#include <strings.h>\n#endif \n#ifdef HAVE_UNISTD_H\n#include <unistd.h>\n#endif\n#ifdef HAVE_SIGNAL_H\n#include <signal.h>\n#endif\n#ifdef HAVE_ERRNO_H\n#include <errno.h>\n#endif\n#ifdef HAVE_STDLIB_H\n#include <stdlib.h>\n#endif\n#ifdef HAVE_FCNTL_H\n#include <fcntl.h>\n#endif\n\n#ifdef HAVE_SOCKS_H\n#include <socks.h>\n#endif\n\n#ifdef HAVE_OPENSSL\n#include <openssl/ssl.h>\n#include <openssl/err.h>\n#include <openssl/pkcs12.h> /* for PKCS12_PBE_add */\n#include <openssl/rand.h>\n#include <openssl/opensslv.h> /* for OPENSSL_VERSION_NUMBER */\n#endif\n\n#ifdef HAVE_GNUTLS\n#include <gnutls/gnutls.h>\n#endif\n\n#define NE_INET_ADDR_DEFINED\n/* A slightly ugly hack: change the ne_inet_addr definition to be the\n * real address type used.  The API only exposes ne_inet_addr as a\n * pointer to an opaque object, so this should be well-defined\n * behaviour.  It avoids the hassle of a real wrapper ne_inet_addr\n * structure, or losing type-safety by using void *. */\n#ifdef USE_GETADDRINFO\ntypedef struct addrinfo ne_inet_addr;\n#else\ntypedef struct in_addr ne_inet_addr;\n#endif\n\n#include \"ne_privssl.h\" /* MUST come after ne_inet_addr is defined */\n\n/* To avoid doing AAAA queries unless absolutely necessary, either use\n * AI_ADDRCONFIG where available, or a run-time check for working IPv6\n * support; the latter is only known to work on Linux. */\n#if defined(USE_GETADDRINFO) && !defined(USE_GAI_ADDRCONFIG) && defined(__linux__)\n#define USE_CHECK_IPV6\n#endif\n\n/* \"Be Conservative In What You Build\". */\n#if defined(HAVE_FCNTL) && defined(O_NONBLOCK) && defined(F_SETFL) \\\n    && defined(HAVE_GETSOCKOPT) && defined(SO_ERROR) \\\n    && defined(HAVE_SOCKLEN_T) && defined(SOL_SOCKET) \\\n    && defined(EINPROGRESS)\n#define USE_NONBLOCKING_CONNECT\n#endif\n\n#include \"ne_internal.h\"\n#include \"ne_utils.h\"\n#include \"ne_string.h\"\n#include \"ne_socket.h\"\n#include \"ne_alloc.h\"\n#include \"ne_sspi.h\"\n\n#if defined(__BEOS__) && !defined(BONE_VERSION)\n/* pre-BONE */\n#define ne_close(s) closesocket(s)\n#define ne_errno errno\n#elif defined(WIN32)\n#define ne_close(s) closesocket(s)\n#define ne_errno WSAGetLastError()\n#else /* really Unix! */\n#define ne_close(s) close(s)\n#define ne_errno errno\n#endif\n\n#ifdef WIN32\n#define NE_ISRESET(e) ((e) == WSAECONNABORTED || (e) == WSAETIMEDOUT || \\\n                       (e) == WSAECONNRESET || (e) == WSAENETRESET)\n#define NE_ISCLOSED(e) ((e) == WSAESHUTDOWN || (e) == WSAENOTCONN)\n#define NE_ISINTR(e) (0)\n#define NE_ISINPROGRESS(e) ((e) == WSAEWOULDBLOCK) /* says MSDN */\n#else /* Unix */\n/* Also treat ECONNABORTED and ENOTCONN as \"connection reset\" errors;\n * both can be returned by Winsock-based sockets layers e.g. CygWin */\n#ifndef ECONNABORTED\n#define ECONNABORTED ECONNRESET\n#endif\n#ifndef ENOTCONN\n#define ENOTCONN ECONNRESET\n#endif\n#define NE_ISRESET(e) ((e) == ECONNRESET || (e) == ECONNABORTED || (e) == ENOTCONN)\n#define NE_ISCLOSED(e) ((e) == EPIPE)\n#define NE_ISINTR(e) ((e) == EINTR)\n#define NE_ISINPROGRESS(e) ((e) == EINPROGRESS)\n#endif\n\n/* Socket read timeout */\n#define SOCKET_READ_TIMEOUT 120\n\n/* Critical I/O functions on a socket: useful abstraction for easily\n * handling SSL I/O alongside raw socket I/O. */\nstruct iofns {\n    /* Read up to 'len' bytes into 'buf' from socket.  Return <0 on\n     * error or EOF, or >0; number of bytes read. */\n    ssize_t (*sread)(ne_socket *s, char *buf, size_t len);\n    /* Write up to 'len' bytes from 'buf' to socket.  Return number of\n     * bytes written on success, or <0 on error. */\n    ssize_t (*swrite)(ne_socket *s, const char *buf, size_t len);\n    /* Wait up to 'n' seconds for socket to become readable.  Returns\n     * 0 when readable, otherwise NE_SOCK_TIMEOUT or NE_SOCK_ERROR. */\n    int (*readable)(ne_socket *s, int n);\n    /* Write up to 'count' blocks described by 'vector' to socket.\n     * Return number of bytes written on success, or <0 on error. */\n    ssize_t (*swritev)(ne_socket *s, const struct ne_iovec *vector, \n                       int count);\n};\n\nstatic const ne_inet_addr dummy_laddr;\n\nstruct ne_socket_s {\n    int fd;\n    unsigned int lport;\n    const ne_inet_addr *laddr;\n\n    void *progress_ud;\n    int rdtimeout, cotimeout; /* timeouts */\n    const struct iofns *ops;\n#ifdef NE_HAVE_SSL\n    ne_ssl_socket ssl;\n#endif\n    /* The read buffer: ->buffer stores byte which have been read; as\n     * these are consumed and passed back to the caller, bufpos\n     * advances through ->buffer.  ->bufavail gives the number of\n     * bytes which remain to be consumed in ->buffer (from ->bufpos),\n     * and is hence always <= RDBUFSIZ. */\n    char *bufpos;\n#define RDBUFSIZ 4096\n    char buffer[RDBUFSIZ];\n    size_t bufavail;\n    /* Error string. */\n    char error[192];\n};\n\n/* ne_sock_addr represents an Internet address. */\nstruct ne_sock_addr_s {\n#ifdef USE_GETADDRINFO\n    struct addrinfo *result, *cursor;\n#else\n    struct in_addr *addrs;\n    size_t cursor, count;\n    char *name;\n#endif\n    int errnum;\n};\n\n/* set_error: set socket error string to 'str'. */\n#define set_error(s, str) ne_strnzcpy((s)->error, (str), sizeof (s)->error)\n\n/* set_strerror: set socket error to system error string for 'errnum' */\n#ifdef WIN32\n/* Print system error message to given buffer. */\nstatic void print_error(int errnum, char *buffer, size_t buflen)\n{\n    if (FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM\n                       | FORMAT_MESSAGE_IGNORE_INSERTS,\n                       NULL, (DWORD) errnum, 0, \n                       buffer, buflen, NULL) == 0)\n        ne_snprintf(buffer, buflen, \"Socket error %d\", errnum);\n}\n#define set_strerror(s, e) print_error((e), (s)->error, sizeof (s)->error)\n#else /* not WIN32 */\n#define set_strerror(s, e) ne_strerror((e), (s)->error, sizeof (s)->error)\n#endif\n\n#ifdef HAVE_OPENSSL\n/* Seed the SSL PRNG, if necessary; returns non-zero on failure. */\nstatic int seed_ssl_prng(void)\n{\n    /* Check whether the PRNG has already been seeded. */\n    if (RAND_status() == 1)\n\treturn 0;\n\n#if defined(EGD_PATH)\n    NE_DEBUG(NE_DBG_SOCKET, \"Seeding PRNG from \" EGD_PATH \"...\\n\");\n    if (RAND_egd(EGD_PATH) != -1)\n\treturn 0;\n#elif defined(ENABLE_EGD)\n    {\n\tstatic const char *paths[] = { \"/var/run/egd-pool\", \"/dev/egd-pool\",\n\t\t\t\t       \"/etc/egd-pool\", \"/etc/entropy\" };\n\tsize_t n;\n\tfor (n = 0; n < sizeof(paths) / sizeof(char *); n++) {\n\t    NE_DEBUG(NE_DBG_SOCKET, \"Seeding PRNG from %s...\\n\", paths[n]);\n\t    if (RAND_egd(paths[n]) != -1)\n\t\treturn 0;\n\t}\n    }\n#endif /* EGD_PATH */\n\n    NE_DEBUG(NE_DBG_SOCKET, \"No entropy source found; could not seed PRNG.\\n\");\n    return -1;\n}\n#endif /* HAVE_OPENSSL */\n\n#ifdef USE_CHECK_IPV6\nstatic int ipv6_disabled = 0;\n\n/* On Linux kernels, IPv6 is typically built as a loadable module, and\n * socket(AF_INET6, ...) will fail if this module is not loaded, so\n * the slow AAAA lookups can be avoided for this common case. */\nstatic void init_ipv6(void)\n{\n    int fd = socket(AF_INET6, SOCK_STREAM, 0);\n    \n    if (fd < 0)\n        ipv6_disabled = 1;\n    else\n        close(fd);\n}\n#elif defined(AF_INET6)\n#define ipv6_disabled (0)\n#else\n#define ipv6_disabled (1)\n#endif\n\n/* If init_state is N where > 0, ne_sock_init has been called N times;\n * if == 0, library is not initialized; if < 0, library initialization\n * has failed. */\nstatic int init_state = 0;\n\nint ne_sock_init(void)\n{\n#ifdef WIN32\n    WORD wVersionRequested;\n    WSADATA wsaData;\n    int err;\n#endif\n\n    if (init_state > 0) {\n        init_state++;\n\treturn 0;\n    } \n    else if (init_state < 0) {\n\treturn -1;\n    }\n\n#ifdef WIN32    \n    wVersionRequested = MAKEWORD(2, 2);\n    \n    err = WSAStartup(wVersionRequested, &wsaData);\n    if (err != 0) {\n\treturn init_state = -1;\n    }\n#ifdef HAVE_SSPI\n    if (ne_sspi_init() < 0) {\n        return init_state = -1;\n    }\n#endif\n#endif\n\n#ifdef NE_HAVE_SOCKS\n    SOCKSinit(\"neon\");\n#endif\n\n#if defined(HAVE_SIGNAL) && defined(SIGPIPE)\n    (void) signal(SIGPIPE, SIG_IGN);\n#endif\n\n#ifdef USE_CHECK_IPV6\n    init_ipv6();\n#endif\n\n#ifdef NE_HAVE_SSL\n    if (ne__ssl_init()) {\n        return init_state = -1;\n    }\n#endif\n\n    init_state = 1;\n    return 0;\n}\n\nvoid ne_sock_exit(void)\n{\n    if (init_state > 0 && --init_state == 0) {\n#ifdef WIN32\n        WSACleanup();\n#endif\n#ifdef NE_HAVE_SSL\n        ne__ssl_exit();\n#endif\n        \n#ifdef HAVE_SSPI\n        ne_sspi_deinit();\n#endif\n    }\n}\n\n/* Await readability (rdwr = 0) or writability (rdwr != 0) for socket\n * fd for secs seconds.  Returns <0 on error, zero on timeout, >0 if\n * data is available. */\nstatic int raw_poll(int fdno, int rdwr, int secs)\n{\n    int ret;\n#ifdef NE_USE_POLL\n    struct pollfd fds;\n    int timeout = secs > 0 ? secs * 1000 : -1;\n\n    fds.fd = fdno;\n    fds.events = rdwr == 0 ? POLLIN : POLLOUT;\n    fds.revents = 0;\n\n    do {\n        ret = poll(&fds, 1, timeout);\n    } while (ret < 0 && NE_ISINTR(ne_errno));\n#else\n    fd_set rdfds, wrfds, exfds;\n    struct timeval timeout, *tvp = (secs >= 0 ? &timeout : NULL);\n\n    /* Init the fd set */\n    FD_ZERO(&rdfds);\n    FD_ZERO(&wrfds);\n    FD_ZERO(&exfds);\n\n    /* Note that (amazingly) the FD_SET macro does not expand\n     * correctly on Netware if not inside a compound statement\n     * block. */\n    if (rdwr == 0) {\n        FD_SET(fdno, &rdfds);\n    } else {\n        FD_SET(fdno, &wrfds);\n    }\n    FD_SET(fdno, &exfds);\n\n    if (tvp) {\n        tvp->tv_sec = secs;\n        tvp->tv_usec = 0;\n    }\n    do {\n\tret = select(fdno + 1, &rdfds, &wrfds, &exfds, tvp);\n    } while (ret < 0 && NE_ISINTR(ne_errno));\n#endif\n    return ret;\n}\n\nint ne_sock_block(ne_socket *sock, int n)\n{\n    if (sock->bufavail)\n\treturn 0;\n    return sock->ops->readable(sock, n);\n}\n\n/* Cast address object AD to type 'sockaddr_TY' */ \n#define SACAST(ty, ad) ((struct sockaddr_##ty *)(ad))\n\nssize_t ne_sock_read(ne_socket *sock, char *buffer, size_t buflen)\n{\n    ssize_t bytes;\n\n#if 0\n    NE_DEBUG(NE_DBG_SOCKET, \"buf: at %d, %d avail [%s]\\n\", \n\t     sock->bufpos - sock->buffer, sock->bufavail, sock->bufpos);\n#endif\n\n    if (sock->bufavail > 0) {\n\t/* Deliver buffered data. */\n\tif (buflen > sock->bufavail)\n\t    buflen = sock->bufavail;\n\tmemcpy(buffer, sock->bufpos, buflen);\n\tsock->bufpos += buflen;\n\tsock->bufavail -= buflen;\n\treturn buflen;\n    } else if (buflen >= sizeof sock->buffer) {\n\t/* No need for read buffer. */\n\treturn sock->ops->sread(sock, buffer, buflen);\n    } else {\n\t/* Fill read buffer. */\n\tbytes = sock->ops->sread(sock, sock->buffer, sizeof sock->buffer);\n\tif (bytes <= 0)\n\t    return bytes;\n\n\tif (buflen > (size_t)bytes)\n\t    buflen = bytes;\n\tmemcpy(buffer, sock->buffer, buflen);\n\tsock->bufpos = sock->buffer + buflen;\n\tsock->bufavail = bytes - buflen;\n\treturn buflen; \n    }\n}\n\nssize_t ne_sock_peek(ne_socket *sock, char *buffer, size_t buflen)\n{\n    ssize_t bytes;\n    \n    if (sock->bufavail) {\n\t/* just return buffered data. */\n\tbytes = sock->bufavail;\n    } else {\n\t/* fill the buffer. */\n\tbytes = sock->ops->sread(sock, sock->buffer, sizeof sock->buffer);\n\tif (bytes <= 0)\n\t    return bytes;\n\n\tsock->bufpos = sock->buffer;\n\tsock->bufavail = bytes;\n    }\n\n    if (buflen > (size_t)bytes)\n\tbuflen = bytes;\n\n    memcpy(buffer, sock->bufpos, buflen);\n\n    return buflen;\n}\n\n/* Await data on raw fd in socket. */\nstatic int readable_raw(ne_socket *sock, int secs)\n{\n    int ret = raw_poll(sock->fd, 0, secs);\n\n    if (ret < 0) {\n\tset_strerror(sock, ne_errno);\n\treturn NE_SOCK_ERROR;\n    }\n    return (ret == 0) ? NE_SOCK_TIMEOUT : 0;\n}\n\nstatic ssize_t read_raw(ne_socket *sock, char *buffer, size_t len)\n{\n    ssize_t ret;\n    \n    ret = readable_raw(sock, sock->rdtimeout);\n    if (ret) return ret;\n\n    do {\n\tret = recv(sock->fd, buffer, len, 0);\n    } while (ret == -1 && NE_ISINTR(ne_errno));\n\n    if (ret == 0) {\n\tset_error(sock, _(\"Connection closed\"));\n\tret = NE_SOCK_CLOSED;\n    } else if (ret < 0) {\n\tint errnum = ne_errno;\n\tret = NE_ISRESET(errnum) ? NE_SOCK_RESET : NE_SOCK_ERROR;\n\tset_strerror(sock, errnum);\n    }\n\n    return ret;\n}\n\n#define MAP_ERR(e) (NE_ISCLOSED(e) ? NE_SOCK_CLOSED : \\\n                    (NE_ISRESET(e) ? NE_SOCK_RESET : NE_SOCK_ERROR))\n\n#ifdef MSG_NOSIGNAL\n#define SEND_FLAGS MSG_NOSIGNAL\n#else\n#define SEND_FLAGS (0)\n#endif\n\nstatic ssize_t write_raw(ne_socket *sock, const char *data, size_t length) \n{\n    ssize_t ret;\n    \n#ifdef __QNX__\n    /* Test failures seen on QNX over loopback, if passing large\n     * buffer lengths to send().  */\n    if (length > 8192) length = 8192;\n#endif\n\n    do {\n\tret = send(sock->fd, data, length, SEND_FLAGS);\n    } while (ret == -1 && NE_ISINTR(ne_errno));\n\n    if (ret < 0) {\n\tint errnum = ne_errno;\n\tset_strerror(sock, errnum);\n\treturn MAP_ERR(errnum);\n    }\n    return ret;\n}\n\nstatic ssize_t writev_raw(ne_socket *sock, const struct ne_iovec *vector, int count) \n{\n    ssize_t ret;\n#ifdef WIN32\n    LPWSABUF wasvector = (LPWSABUF)ne_malloc(count * sizeof(WSABUF));\n    DWORD total;\n    int i;\n\n    for (i = 0; i < count; i++){\n        wasvector[i].buf = vector[i].base;\n        wasvector[i].len = vector[i].len;\n    }\n        \n    ret = WSASend(sock->fd, wasvector, count, &total, 0, NULL, NULL);\n    if (ret == 0)\n        ret = total;\n    \n    ne_free(wasvector);\n#elif defined(MSG_NOSIGNAL) && defined(HAVE_SENDMSG)\n    struct msghdr m;\n\n    memset(&m, 0, sizeof m);\n    m.msg_iov = (struct iovec *)vector;\n    m.msg_iovlen = count;\n\n    do {\n\tret = sendmsg(sock->fd, &m, MSG_NOSIGNAL);\n    } while (ret == -1 && NE_ISINTR(ne_errno));\n\n#else\n    const struct iovec *vec = (const struct iovec *) vector;\n\n    do {\n\tret = writev(sock->fd, vec, count);\n    } while (ret == -1 && NE_ISINTR(ne_errno));\n#endif\n\n    if (ret < 0) {\n\tint errnum = ne_errno;\n\tset_strerror(sock, errnum);\n\treturn MAP_ERR(errnum);\n    }\n    \n    return ret;\n}\n\n#ifdef NE_HAVE_SSL\nstatic ssize_t writev_dummy(ne_socket *sock, const struct ne_iovec *vector, int count) \n{\n    return sock->ops->swrite(sock, vector[0].base, vector[0].len);\n}\n#endif\n\nstatic const struct iofns iofns_raw = { read_raw, write_raw, readable_raw, writev_raw };\n\n#ifdef HAVE_OPENSSL\nstatic int error_ossl(ne_socket *sock, int sret);\n#define sock_ssl(s_) ((s_)->ssl.ssl)\n#endif\n\n#ifdef HAVE_OPENSSL\n/* OpenSSL I/O function implementations. */\nstatic int readable_ossl(ne_socket *sock, int secs)\n{\n#if defined(LIBRESSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER < 0x10101000L\n    /* Sufficient for TLSv1.2 and earlier. */\n    if (SSL_pending(sock_ssl(sock)))\n\treturn 0;\n    return readable_raw(sock, secs);\n#else\n    /* TLSv1.3 sends a lot more handshake data so the presence of data\n     * on the socket - i.e. poll() returning 1, is an insufficient\n     * test for app-data readability. */\n    char pending;\n    int ret;\n    size_t bytes;\n\n    /* Loop while no app data is pending, each time attempting a one\n     * byte peek, and retrying the poll if that fails due to absence\n     * of app data. */\n    while (!SSL_pending(sock_ssl(sock))) {\n\tret = readable_raw(sock, secs);\n\tif (ret == NE_SOCK_TIMEOUT) {\n\t    return ret;\n\t}\n        \n\tret = SSL_peek_ex(sock_ssl(sock), &pending, 1, &bytes);\n\tif (ret) {\n            /* App data definitely available. */\n\t    break;\n\t}\n\telse {\n            /* If this gave SSL_ERROR_WANT_READ, loop and probably\n             * block again, else some other error happened. */\n            ret = error_ossl(sock, ret);\n            if (ret != NE_SOCK_RETRY)\n                return ret;\n\t}\n    }\n\n    return 0;\n#endif /* OPENSSL_VERSION_NUMBER < 1.1.1 */\n}\n\n/* SSL error handling, according to SSL_get_error(3). */\nstatic int error_ossl(ne_socket *sock, int sret)\n{\n    int errnum = SSL_get_error(sock_ssl(sock), sret), reason;\n    unsigned long err;\n\n    if (errnum == SSL_ERROR_ZERO_RETURN) {\n        set_error(sock, _(\"Connection closed\"));\n        NE_DEBUG(NE_DBG_SSL, \"ssl: Got TLS closure.\\n\");\n        return NE_SOCK_CLOSED;\n    }\n    else if (errnum == SSL_ERROR_WANT_READ) {\n        set_error(sock, _(\"Retry operation\"));\n        return NE_SOCK_RETRY;\n    }\n    \n    /* for all other errors, look at the OpenSSL error stack */\n    err = ERR_get_error();\n    reason = ERR_GET_REASON(err);\n    NE_DEBUG(NE_DBG_SSL, \"ssl: Got OpenSSL error %lu (library=%d, reason=%d)\\n\",\n             err, ERR_GET_LIB(err), reason);\n\n    switch (ERR_GET_LIB(err)) {\n    case ERR_LIB_SSL:\n#ifdef SSL_R_UNEXPECTED_EOF_WHILE_READING\n        /* OpenSSL 3 signals truncation this way. */\n\tif (reason == SSL_R_UNEXPECTED_EOF_WHILE_READING) {\n\t    set_error(sock, _(\"Secure connection truncated\"));\n\t    return NE_SOCK_TRUNC;\n\t}\n#endif\n\tif (reason == SSL_R_PROTOCOL_IS_SHUTDOWN) {\n\t    set_error(sock, _(\"Secure connection reset\"));\n\t    return NE_SOCK_RESET;\n\t}\n#ifdef SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED\n        if (reason == SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED) {\n            set_error(sock, _(\"Handshake rejected - client certificate \"\n                              \"was requested\"));\n            return NE_SOCK_ERROR;\n        }\n#endif\n#ifdef SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE\n        if (reason == SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE) {\n            if (sock->ssl.cc_requested)\n                set_error(sock, _(\"Handshake rejected - client certificate \"\n                                  \"was requested\"));\n            else\n                set_error(sock, _(\"Handshake failed\"));\n            return NE_SOCK_ERROR;\n        }\n#endif\n        break;\n    case ERR_LIB_SYS:\n        set_strerror(sock, reason);\n        return MAP_ERR(reason);\n    }\n\n    if (err == 0) {\n        /* Empty error stack, presume this is a system call error: */\n        if (sret == 0) {\n            /* EOF without close_notify, possible truncation */\n            set_error(sock, _(\"Secure connection truncated\"));\n            return NE_SOCK_TRUNC;\n        } else {\n            /* Other socket error. */\n            errnum = ne_errno;\n            set_strerror(sock, errnum);\n            return MAP_ERR(errnum);\n        }\n    }\n\n    if (ERR_reason_error_string(err)) {\n        ne_snprintf(sock->error, sizeof sock->error, \n                    _(\"SSL error: %s\"), ERR_reason_error_string(err));\n    } else {\n\tne_snprintf(sock->error, sizeof sock->error, \n                    _(\"SSL error code %d/%d/%lu\"), sret, errnum, err);\n    }\n    \n    /* make sure the error stack is now empty. */\n    ERR_clear_error();\n    return NE_SOCK_ERROR;\n}\n\n/* Work around OpenSSL's use of 'int' rather than 'size_t', to prevent\n * accidentally passing a negative number, etc. */\n#define CAST2INT(n) (((n) > INT_MAX) ? INT_MAX : (n))\n\nstatic ssize_t read_ossl(ne_socket *sock, char *buffer, size_t len)\n{\n    int ret;\n\n    do {\n        ret = readable_ossl(sock, sock->rdtimeout);\n        if (ret) return ret;\n        \n        ret = SSL_read(sock_ssl(sock), buffer, CAST2INT(len));\n        if (ret <= 0)\n            ret = error_ossl(sock, ret);\n    } while (ret == NE_SOCK_RETRY);\n        \n    return ret;\n}\n\nstatic ssize_t write_ossl(ne_socket *sock, const char *data, size_t len)\n{\n    int ret, ilen = CAST2INT(len);\n    ret = SSL_write(sock_ssl(sock), data, ilen);\n    /* ssl.h says SSL_MODE_ENABLE_PARTIAL_WRITE must be enabled to\n     * have SSL_write return < length...  so, SSL_write should never\n     * return < length. */\n    if (ret != ilen)\n\treturn error_ossl(sock, ret);\n    return ret;\n}\n\nstatic const struct iofns iofns_ssl = {\n    read_ossl,\n    write_ossl,\n    readable_ossl,\n    writev_dummy\n};\n\n#elif defined(HAVE_GNUTLS)\n\n#define sock_ssl(s_) ((s_)->ssl.sess)\n\n/* Return zero if an alert value can be ignored. */\nstatic int check_alert(ne_socket *sock, ssize_t ret)\n{\n    const char *alert;\n\n    if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED) {\n        alert = gnutls_alert_get_name(gnutls_alert_get(sock_ssl(sock)));\n        NE_DEBUG(NE_DBG_SOCKET, \"TLS warning alert: %s\\n\", alert);\n        return 0;\n    } else if (ret == GNUTLS_E_FATAL_ALERT_RECEIVED) {\n        alert = gnutls_alert_get_name(gnutls_alert_get(sock_ssl(sock)));\n        NE_DEBUG(NE_DBG_SOCKET, \"TLS fatal alert: %s\\n\", alert);\n        return -1;\n    }\n    return ret;\n}\n\nstatic int readable_gnutls(ne_socket *sock, int secs)\n{\n    if (gnutls_record_check_pending(sock_ssl(sock))) {\n        return 0;\n    }\n    return readable_raw(sock, secs);\n}\n\nstatic ssize_t error_gnutls(ne_socket *sock, ssize_t sret)\n{\n    const char *note = \"\";\n    ssize_t ret;\n\n    switch (sret) {\n    case 0:\n\tret = NE_SOCK_CLOSED;\n\tset_error(sock, _(\"Connection closed\"));\n\tbreak;\n    case GNUTLS_E_FATAL_ALERT_RECEIVED:\n        ret = NE_SOCK_ERROR;\n        ne_snprintf(sock->error, sizeof sock->error, \n                    _(\"SSL alert received: %s\"),\n                    gnutls_alert_get_name(gnutls_alert_get(sock_ssl(sock))));\n        break;\n#if GNUTLS_VERSION_MAJOR > 2 || (GNUTLS_VERSION_MAJOR == 2 && GNUTLS_VERSION_MINOR >= 99)\n    case GNUTLS_E_PREMATURE_TERMINATION:\n#else\n    case GNUTLS_E_UNEXPECTED_PACKET_LENGTH:\n#endif\n        ret = NE_SOCK_TRUNC;\n        set_error(sock, _(\"Secure connection truncated\"));\n        break;\n    case GNUTLS_E_INVALID_SESSION:\n        ret = NE_SOCK_RESET;\n        set_error(sock, (\"SSL socket terminated\"));\n        break;\n    case GNUTLS_E_PUSH_ERROR:\n        ret = NE_SOCK_RESET;\n        set_error(sock, (\"SSL socket write failed\"));\n        break;\n    case GNUTLS_E_PULL_ERROR:\n        ret = NE_SOCK_RESET;\n        set_error(sock, _(\"SSL socket read failed\"));\n        break;\n    case GNUTLS_E_UNEXPECTED_PACKET:\n        if (sock->ssl.cc_requested)\n            note = _(\" (client certificate was requested)\");\n        /* fallthrough */\n    default:\n        ret = NE_SOCK_ERROR;\n        ne_snprintf(sock->error, sizeof sock->error, _(\"SSL error%s: %s\"),\n                    note, gnutls_strerror(sret));\n    }\n    return ret;\n}\n\n#define RETRY_GNUTLS(sock, ret) ((ret < 0) \\\n    && (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN \\\n        || check_alert(sock, ret) == 0))\n\nstatic ssize_t read_gnutls(ne_socket *sock, char *buffer, size_t len)\n{\n    ssize_t ret;\n    unsigned reneg = 1; /* number of allowed rehandshakes */\n\n    ret = readable_gnutls(sock, sock->rdtimeout);\n    if (ret) return ret;\n    \n    do {\n        do {\n            ret = gnutls_record_recv(sock_ssl(sock), buffer, len);\n        } while (RETRY_GNUTLS(sock, ret));\n    } while (ret == GNUTLS_E_REHANDSHAKE && reneg--\n             && (ret = gnutls_handshake(sock_ssl(sock))) == GNUTLS_E_SUCCESS);\n\n    if (ret <= 0)\n\tret = error_gnutls(sock, ret);\n\n    return ret;\n}\n\nstatic ssize_t write_gnutls(ne_socket *sock, const char *data, size_t len)\n{\n    ssize_t ret;\n\n    do {\n        ret = gnutls_record_send(sock_ssl(sock), data, len);\n    } while (RETRY_GNUTLS(sock, ret));\n\n    if (ret < 0)\n\treturn error_gnutls(sock, ret);\n\n    return ret;\n}\n\nstatic const struct iofns iofns_ssl = {\n    read_gnutls,\n    write_gnutls,\n    readable_gnutls,\n    writev_dummy\n};\n\n#endif\n\nint ne_sock_fullwrite(ne_socket *sock, const char *data, size_t len)\n{\n    ssize_t ret;\n\n    do {\n        ret = sock->ops->swrite(sock, data, len);\n        if (ret > 0) {\n            data += ret;\n            len -= ret;\n        }\n    } while (ret > 0 && len > 0);\n\n    return ret < 0 ? ret : 0;\n}\n\nint ne_sock_fullwritev(ne_socket *sock, const struct ne_iovec *vector, int count)\n{\n    ssize_t ret;\n\n    do {\n        ret = sock->ops->swritev(sock, vector, count);\n        if (ret > 0) {\n            while (count && (size_t)ret >= vector[0].len) {\n                ret -= vector[0].len;\n                count--;\n                vector++;\n            }\n            \n            if (ret && count) {\n                /* Partial buffer sent; send the rest. */\n                ret = ne_sock_fullwrite(sock, (char *)vector[0].base + ret,\n                                        vector[0].len - ret);\n                count--;\n                vector++;\n            }\n        }\n    } while (count && ret >= 0);\n\n    return ret < 0 ? ret : 0;\n}\n\nssize_t ne_sock_readline(ne_socket *sock, char *buf, size_t buflen)\n{\n    char *lf;\n    size_t len;\n    \n    if ((lf = memchr(sock->bufpos, '\\n', sock->bufavail)) == NULL\n\t&& sock->bufavail < RDBUFSIZ) {\n\t/* The buffered data does not contain a complete line: move it\n\t * to the beginning of the buffer. */\n\tif (sock->bufavail)\n\t    memmove(sock->buffer, sock->bufpos, sock->bufavail);\n\tsock->bufpos = sock->buffer;\n\t\n\t/* Loop filling the buffer whilst no newline is found in the data\n\t * buffered so far, and there is still buffer space available */ \n\tdo {\n\t    /* Read more data onto end of buffer. */\n\t    ssize_t ret = sock->ops->sread(sock, sock->buffer + sock->bufavail,\n                                           RDBUFSIZ - sock->bufavail);\n\t    if (ret < 0) return ret;\n\t    sock->bufavail += ret;\n\t} while ((lf = memchr(sock->buffer, '\\n', sock->bufavail)) == NULL\n\t\t && sock->bufavail < RDBUFSIZ);\n    }\n\n    if (lf)\n\tlen = lf - sock->bufpos + 1;\n    else\n\tlen = buflen; /* fall into \"line too long\" error... */\n\n    if ((len + 1) > buflen) {\n\tset_error(sock, _(\"Line too long\"));\n\treturn NE_SOCK_ERROR;\n    }\n\n    memcpy(buf, sock->bufpos, len);\n    buf[len] = '\\0';\n    /* consume the line from buffer: */\n    sock->bufavail -= len;\n    sock->bufpos += len;\n    return len;\n}\n\nssize_t ne_sock_fullread(ne_socket *sock, char *buffer, size_t buflen) \n{\n    ssize_t len;\n\n    while (buflen > 0) {\n\tlen = ne_sock_read(sock, buffer, buflen);\n\tif (len < 0) return len;\n\tbuflen -= len;\n\tbuffer += len;\n    }\n\n    return 0;\n}\n\n#ifndef INADDR_NONE\n#define INADDR_NONE ((in_addr_t) -1)\n#endif\n\n#if !defined(USE_GETADDRINFO) && !defined(WIN32) && !HAVE_DECL_H_ERRNO\n/* Ancient versions of netdb.h don't export h_errno. */\nextern int h_errno;\n#endif\n\n/* This implementation does not attempt to support IPv6 using\n * gethostbyname2 et al.  */\nne_sock_addr *ne_addr_resolve(const char *hostname, int flags)\n{\n    ne_sock_addr *addr = ne_calloc(sizeof *addr);\n#ifdef USE_GETADDRINFO\n    struct addrinfo hints = {0};\n    const char *pnt;\n\n    hints.ai_socktype = SOCK_STREAM;\n\n    if (flags & NE_ADDR_CANON) {\n        hints.ai_flags = AI_CANONNAME;\n    }\n\n#ifdef AF_INET6\n    if (hostname[0] == '[' && ((pnt = strchr(hostname, ']')) != NULL)) {\n\tchar *hn = ne_strdup(hostname + 1);\n\thn[pnt - hostname - 1] = '\\0';\n#ifdef AI_NUMERICHOST /* added in the RFC2553 API */\n\thints.ai_flags |= AI_NUMERICHOST;\n#endif\n        hints.ai_family = AF_INET6;\n\taddr->errnum = getaddrinfo(hn, NULL, &hints, &addr->result);\n\tne_free(hn);\n    } else \n#endif /* AF_INET6 */\n    {\n#ifdef USE_GAI_ADDRCONFIG /* added in the RFC3493 API */\n        hints.ai_flags |= AI_ADDRCONFIG;\n        hints.ai_family = AF_UNSPEC;\n        addr->errnum = getaddrinfo(hostname, NULL, &hints, &addr->result);\n#else\n        hints.ai_family = ipv6_disabled ? AF_INET : AF_UNSPEC;\n\taddr->errnum = getaddrinfo(hostname, NULL, &hints, &addr->result);\n#endif\n    }\n#else /* Use gethostbyname() */\n    in_addr_t laddr;\n    struct hostent *hp;\n    \n    laddr = inet_addr(hostname);\n    if (laddr == INADDR_NONE) {\n\thp = gethostbyname(hostname);\n\tif (hp == NULL) {\n#ifdef WIN32\n\t    addr->errnum = WSAGetLastError();\n#else\n            addr->errnum = h_errno;\n#endif\n\t} else if (hp->h_length != sizeof(struct in_addr)) {\n\t    /* fail gracefully if somebody set RES_USE_INET6 */\n\t    addr->errnum = NO_RECOVERY;\n\t} else {\n\t    size_t n;\n\t    /* count addresses */\n\t    for (n = 0; hp->h_addr_list[n] != NULL; n++)\n\t\t/* noop */;\n\n\t    addr->count = n;\n\t    addr->addrs = ne_malloc(n * sizeof *addr->addrs);\n\n\t    for (n = 0; n < addr->count; n++)\n\t\tmemcpy(&addr->addrs[n], hp->h_addr_list[n], hp->h_length);\n            \n            if (hp->h_name && hp->h_name[0]) \n                addr->name = ne_strdup(hp->h_name);\n\t}\n    } else {\n\taddr->addrs = ne_malloc(sizeof *addr->addrs);\n\taddr->count = 1;\n\tmemcpy(addr->addrs, &laddr, sizeof *addr->addrs);\n    }\n#endif\n    return addr;\n}\n\nint ne_addr_result(const ne_sock_addr *addr)\n{\n    return addr->errnum;\n}\n\nconst char *ne_addr_canonical(const ne_sock_addr *addr)\n{\n#ifdef USE_GETADDRINFO\n    return addr->result ? addr->result->ai_canonname : NULL;\n#else\n    return addr->name;\n#endif\n}\n\nconst ne_inet_addr *ne_addr_first(ne_sock_addr *addr)\n{\n#ifdef USE_GETADDRINFO\n    addr->cursor = addr->result->ai_next;\n    return addr->result;\n#else\n    addr->cursor = 0;\n    return &addr->addrs[0];\n#endif\n}\n\nconst ne_inet_addr *ne_addr_next(ne_sock_addr *addr)\n{\n#ifdef USE_GETADDRINFO\n    struct addrinfo *ret = addr->cursor;\n    if (addr->cursor) addr->cursor = addr->cursor->ai_next;\n#else\n    struct in_addr *ret;\n    if (++addr->cursor < addr->count)\n\tret = &addr->addrs[addr->cursor];\n    else\n\tret = NULL;\n#endif\n    return ret;\n}\n\nchar *ne_addr_error(const ne_sock_addr *addr, char *buf, size_t bufsiz)\n{\n#ifdef WIN32\n    print_error(addr->errnum, buf, bufsiz);\n#else\n    const char *err;\n#ifdef USE_GETADDRINFO\n    /* override horrible generic \"Name or service not known\" error. */\n    if (addr->errnum == EAI_NONAME)\n\terr = _(\"Host not found\");\n    else\n\terr = gai_strerror(addr->errnum);\n#elif defined(HAVE_HSTRERROR)\n    err = hstrerror(addr->errnum);\n#else\n    err = _(\"Host not found\");\n#endif\n    ne_strnzcpy(buf, err, bufsiz);\n#endif /* WIN32 */\n    return buf;\n}\n\nchar *ne_iaddr_print(const ne_inet_addr *ia, char *buf, size_t bufsiz)\n{\n#if defined(USE_GETADDRINFO) && defined(HAVE_INET_NTOP)\n    const char *ret;\n#ifdef AF_INET6\n    if (ia->ai_family == AF_INET6) {\n\tstruct sockaddr_in6 *in6 = SACAST(in6, ia->ai_addr);\n\tret = inet_ntop(AF_INET6, &in6->sin6_addr, buf, bufsiz);\n    } else\n#endif\n    if (ia->ai_family == AF_INET) {\n\tstruct sockaddr_in *in = SACAST(in, ia->ai_addr);\n\tret = inet_ntop(AF_INET, &in->sin_addr, buf, bufsiz);\n    } else\n\tret = NULL;\n    if (ret == NULL)\n\tne_strnzcpy(buf, \"[IP address]\", bufsiz);\n#elif defined(USE_GETADDRINFO) && defined(NI_NUMERICHOST)\n    /* use getnameinfo instead for Win32, which lacks inet_ntop: */\n    if (getnameinfo(ia->ai_addr, ia->ai_addrlen, buf, bufsiz, NULL, 0,\n                    NI_NUMERICHOST))\n        ne_strnzcpy(buf, \"[IP address]\", bufsiz);\n#else /* USE_GETADDRINFO */\n    ne_strnzcpy(buf, inet_ntoa(*ia), bufsiz);\n#endif\n    return buf;\n}\n\nunsigned char *ne_iaddr_raw(const ne_inet_addr *ia, unsigned char *buf)\n{\n#ifdef USE_GETADDRINFO\n#ifdef AF_INET6\n    if (ia->ai_family == AF_INET6) {\n\tstruct sockaddr_in6 *in6 = SACAST(in6, ia->ai_addr);\n        return memcpy(buf, in6->sin6_addr.s6_addr, sizeof in6->sin6_addr.s6_addr);\n    } else\n#endif /* AF_INET6 */\n    {\n\tstruct sockaddr_in *in = SACAST(in, ia->ai_addr);\n        return memcpy(buf, &in->sin_addr.s_addr, sizeof in->sin_addr.s_addr);\n    }\n#else /* !USE_GETADDRINFO */\n    return memcpy(buf, &ia->s_addr, sizeof ia->s_addr);\n#endif\n}\n\nne_inet_addr *ne_iaddr_parse(const char *addr, ne_iaddr_type type)\n{\n#if defined(USE_GETADDRINFO) && defined(HAVE_INET_PTON)\n    char dst[sizeof(struct in6_addr)];\n    int af = type == ne_iaddr_ipv6 ? AF_INET6 : AF_INET;\n\n    if (inet_pton(af, addr, dst) != 1) {\n        return NULL;\n    }\n    \n    return ne_iaddr_make(type, (unsigned char *)dst);\n#elif defined(USE_GETADDRINFO) && !defined(HAVE_INET_PTON)\n    /* For Windows, which lacks inet_pton(). */\n    struct addrinfo *ai, *rv, hints;\n\n    memset(&hints, 0, sizeof hints);\n    hints.ai_socktype = SOCK_STREAM;\n    hints.ai_flags = AI_NUMERICHOST;\n    hints.ai_family = type == ne_iaddr_ipv6 ? AF_INET6 : AF_INET;\n    \n    if (getaddrinfo(addr, NULL, &hints, &ai)) {\n        return NULL;\n    }\n    \n    /* Copy the returned addrinfo, since it needs to be ne_free()-able\n     * later; must only call freeaddrinfo() on ai. */\n    rv = ne_calloc(sizeof *rv);\n    memcpy(rv, ai, sizeof *rv);\n    rv->ai_next = NULL;\n    rv->ai_canonname = NULL;\n    rv->ai_addr = ne_calloc(ai->ai_addrlen);\n    memcpy(rv->ai_addr, ai->ai_addr, ai->ai_addrlen);\n    freeaddrinfo(ai);\n    \n    return rv;    \n#else /* !USE_GETADDRINFO */\n    struct in_addr a;\n    \n    if (type == ne_iaddr_ipv6) {\n        return NULL;\n    }\n\n#ifdef WIN32\n    /* inet_addr() is broken because INADDR_NONE is a valid\n     * broadcast address, so only use it on Windows. */\n    a.s_addr = inet_addr(addr);\n    if (a.s_addr == INADDR_NONE) {\n        return NULL;\n    }\n#else /* !WIN32 */\n    if (inet_aton(addr, &a) == 0) {\n        return NULL;\n    }\n#endif\n    \n    return ne_iaddr_make(ne_iaddr_ipv4, (unsigned char *)&a.s_addr);\n#endif /* !USE_GETADDRINFO */\n}\n\nint ne_iaddr_reverse(const ne_inet_addr *ia, char *buf, size_t bufsiz)\n{\n#ifdef USE_GETADDRINFO\n    return getnameinfo(ia->ai_addr, ia->ai_addrlen, buf, bufsiz,\n                       NULL, 0, 0);\n#else\n    struct hostent *hp;\n    \n    /* Cast to const void *; some old libc headers apparently expect\n     * const char * here. */\n    hp = gethostbyaddr((const void *)ia, sizeof *ia, AF_INET);\n    if (hp && hp->h_name) {\n        ne_strnzcpy(buf, hp->h_name, bufsiz);\n        return 0;\n    }\n    return -1;\n#endif\n}\n\nint ne_iaddr_set_scope(ne_inet_addr *ia, const char *scope)\n{\n#ifdef HAVE_IF_NAMETOINDEX\n    unsigned int idx;\n\n    if (ia->ai_family != AF_INET6) return EINVAL;\n\n    idx = if_nametoindex(scope);\n    if (idx) {\n        struct sockaddr_in6 *in6 = SACAST(in6, ia->ai_addr);\n        in6->sin6_scope_id = idx;\n        return 0;\n    }\n    else\n        return errno;\n#else\n    return ENODEV;\n#endif\n}\n\nchar *ne_iaddr_get_scope(const ne_inet_addr *ia)\n{\n#ifdef HAVE_IF_INDEXTONAME\n    struct sockaddr_in6 *in6 = SACAST(in6, ia->ai_addr);\n    char buf[IF_NAMESIZE];\n\n    if (ia->ai_family != AF_INET6) return NULL;\n\n    if (in6->sin6_scope_id && if_indextoname(in6->sin6_scope_id, buf) == buf)\n        return ne_strdup(buf);\n#endif\n    return NULL;\n}\n\nvoid ne_addr_destroy(ne_sock_addr *addr)\n{\n#ifdef USE_GETADDRINFO\n    /* Note that ->result is only valid for successful invocations of\n     * getaddrinfo. */\n    if (!addr->errnum && addr->result)\n\tfreeaddrinfo(addr->result);\n#else\n    if (addr->addrs)\n\tne_free(addr->addrs);\n    if (addr->name)\n        ne_free(addr->name);\n#endif\n    ne_free(addr);\n}\n\n/* Perform a connect() for given fd, handling EINTR retries.  Returns\n * zero on success or -1 on failure, in which case, ne_errno is set\n * appropriately. */\nstatic int raw_connect(int fd, const struct sockaddr *sa, size_t salen)\n{\n    int ret;\n\n    do {\n        ret = connect(fd, sa, salen);\n    } while (ret < 0 && NE_ISINTR(ne_errno));\n\n    return ret;\n}\n\n/* Perform a connect() for fd to address sa of length salen, with a\n * timeout if supported on this platform.  Returns zero on success or\n * NE_SOCK_* on failure, with sock->error set appropriately. */\nstatic int timed_connect(ne_socket *sock, int fd,\n                         const struct sockaddr *sa, size_t salen)\n{\n    int ret;\n\n#ifdef USE_NONBLOCKING_CONNECT\n    if (sock->cotimeout) {\n        int errnum, flags;\n\n        /* Get flags and then set O_NONBLOCK. */\n        flags = fcntl(fd, F_GETFL);\n        if (flags & O_NONBLOCK) {\n            /* This socket was created using SOCK_NONBLOCK... flip the\n             * bit for restoring flags later. */\n            flags &= ~O_NONBLOCK;\n        }\n        else if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {\n            set_strerror(sock, errno);\n            return NE_SOCK_ERROR;\n        }\n        \n        ret = raw_connect(fd, sa, salen);\n        if (ret == -1) {\n            errnum = ne_errno;\n            if (NE_ISINPROGRESS(errnum)) {\n                ret = raw_poll(fd, 1, sock->cotimeout);\n                if (ret > 0) { /* poll got data */\n                    socklen_t len = sizeof(errnum);\n                    \n                    /* Check whether there is a pending error for the\n                     * socket.  Per Stevens UNPv1§15.4, Solaris will\n                     * return a pending error via errno by failing the\n                     * getsockopt() call. */\n\n                    errnum = 0;\n                    if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &errnum, &len))\n                        errnum = errno;\n                    \n                    if (errnum == 0) {\n                        ret = 0;\n                    } else {\n                        set_strerror(sock, errnum);\n                        ret = NE_SOCK_ERROR;\n                    }\n                } else if (ret == 0) { /* poll timed out */\n                    set_error(sock, _(\"Connection timed out\"));\n                    ret = NE_SOCK_TIMEOUT;\n                } else /* poll failed */ {\n                    set_strerror(sock, errno);\n                    ret = NE_SOCK_ERROR;\n                }\n            } else /* non-EINPROGRESS error from connect() */ { \n                set_strerror(sock, errnum);\n                ret = NE_SOCK_ERROR;\n            }\n        }\n        \n        /* Reset to old flags; fail on error if no previous error. */\n        if (fcntl(fd, F_SETFL, flags) == -1 && !ret) {\n            set_strerror(sock, errno);\n            ret = NE_SOCK_ERROR;\n        }\n    } else \n#endif /* USE_NONBLOCKING_CONNECT */\n    {\n        ret = raw_connect(fd, sa, salen);\n        \n        if (ret < 0) {\n            set_strerror(sock, ne_errno);\n            ret = NE_SOCK_ERROR;\n        }\n    }\n\n    return ret;\n}\n\n/* Connect socket to address 'addr' on given 'port'.  Returns zero on\n * success or NE_SOCK_* on failure with sock->error set\n * appropriately. */\nstatic int connect_socket(ne_socket *sock, int fd,\n                          const ne_inet_addr *addr, unsigned int port)\n{\n#ifdef USE_GETADDRINFO\n#ifdef AF_INET6\n    /* fill in the _family field for AIX 4.3, which forgets to do so. */\n    if (addr->ai_family == AF_INET6) {\n\tstruct sockaddr_in6 in6;\n\tmemcpy(&in6, addr->ai_addr, sizeof in6);\n\tin6.sin6_port = port;\n        in6.sin6_family = AF_INET6;\n        return timed_connect(sock, fd, (struct sockaddr *)&in6, sizeof in6);\n    } else\n#endif\n    if (addr->ai_family == AF_INET) {\n\tstruct sockaddr_in in;\n\tmemcpy(&in, addr->ai_addr, sizeof in);\n\tin.sin_port = port;\n        in.sin_family = AF_INET;\n        return timed_connect(sock, fd, (struct sockaddr *)&in, sizeof in);\n    } else {\n        set_strerror(sock, EINVAL);\n        return NE_SOCK_ERROR;\n    }\n#else\n    struct sockaddr_in sa = {0};\n    sa.sin_family = AF_INET;\n    sa.sin_port = port;\n    sa.sin_addr = *addr;\n    return timed_connect(sock, fd, (struct sockaddr *)&sa, sizeof sa);\n#endif\n}\n\nne_socket *ne_sock_create(void)\n{\n    ne_socket *sock = ne_calloc(sizeof *sock);\n    sock->rdtimeout = SOCKET_READ_TIMEOUT;\n    sock->cotimeout = 0;\n    sock->bufpos = sock->buffer;\n    sock->ops = &iofns_raw;\n    sock->fd = -1;\n    return sock;\n}\n\n\n#ifdef USE_GETADDRINFO\n#define ia_family(a) ((a)->ai_family)\n#define ia_proto(a)  ((a)->ai_protocol)\n#else\n#define ia_family(a) AF_INET\n#define ia_proto(a)  0\n#endif\n\nvoid ne_sock_prebind(ne_socket *sock, const ne_inet_addr *addr,\n                     unsigned int port)\n{\n    sock->lport = port;\n    sock->laddr = addr ? addr : &dummy_laddr;    \n}\n\n/* Bind socket 'fd' to address/port 'addr' and 'port', for subsequent\n * connect() to address of family 'peer_family'. */\nstatic int do_bind(int fd, int peer_family, \n                   const ne_inet_addr *addr, unsigned int port)\n{\n#if defined(HAVE_SETSOCKOPT) && defined(SO_REUSEADDR) && defined(SOL_SOCKET)\n    {\n        int flag = 1;\n\n        (void) setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof flag);\n        /* An error here is not fatal, so ignore it. */\n    }\n#endif        \n    \n\n#if defined(USE_GETADDRINFO) && defined(AF_INET6)\n    /* Use a sockaddr_in6 if an AF_INET6 local address is specified, or\n     * if no address is specified and the peer address is AF_INET6: */\n    if ((addr != &dummy_laddr && addr->ai_family == AF_INET6)\n        || (addr == &dummy_laddr && peer_family == AF_INET6)) {\n        struct sockaddr_in6 in6;\n        \n        if (addr == &dummy_laddr)\n            memset(&in6, 0, sizeof in6);\n        else\n            memcpy(&in6, addr->ai_addr, sizeof in6);\n        in6.sin6_port = htons(port);\n        /* fill in the _family field for AIX 4.3, which forgets to do so. */\n        in6.sin6_family = AF_INET6;\n#ifdef __NetBSD__\n\tin6.sin6_len = sizeof in6;\n#endif\n\n        return bind(fd, (struct sockaddr *)&in6, sizeof in6);\n    } else\n#endif\n    {\n\tstruct sockaddr_in in;\n\n        if (addr == &dummy_laddr)\n            memset(&in, 0, sizeof in);\n        else {\n#ifdef USE_GETADDRINFO\n            memcpy(&in, addr->ai_addr, sizeof in);\n#else\n            in.sin_addr = *addr;\n#endif\n        }\n        in.sin_port = htons(port);\n        in.sin_family = AF_INET;\n#ifdef __NetBSD__\n\tin.sin_len = sizeof in;\n#endif\n\n        return bind(fd, (struct sockaddr *)&in, sizeof in);\n    }\n}\n\n#ifdef SOCK_CLOEXEC\n/* sock_cloexec is initialized to SOCK_CLOEXEC and cleared to zero if\n * a socket() call ever fails with EINVAL; not strictly thread-safe\n * but in practice it will not matter if two threads race accessing\n * the variable. */\nstatic int sock_cloexec = SOCK_CLOEXEC;\n#define RETRY_ON_EINVAL\n#else\n#define sock_cloexec 0\n#endif\n\nint ne_sock_connect(ne_socket *sock,\n                    const ne_inet_addr *addr, unsigned int port)\n{\n    int fd, ret;\n    int type = SOCK_STREAM | sock_cloexec;\n\n#if defined(RETRY_ON_EINVAL) && defined(SOCK_NONBLOCK) \\\n    && defined(USE_NONBLOCKING_CONNECT)\n    /* If the SOCK_NONBLOCK flag is defined, and the retry-on-EINVAL\n     * logic is enabled, and the socket has a configured timeout, then\n     * also use the SOCK_NONBLOCK flag to save enabling O_NONBLOCK\n     * later. */\n    if (sock->cotimeout && sock_cloexec) {\n        type |= SOCK_NONBLOCK;\n    }\n#endif\n\n    /* use SOCK_STREAM rather than ai_socktype: some getaddrinfo\n     * implementations do not set ai_socktype, e.g. RHL6.2. */\n    fd = socket(ia_family(addr), type, ia_proto(addr));\n#ifdef RETRY_ON_EINVAL\n    /* Handle forwards compat for new glibc on an older kernels; clear\n     * the sock_cloexec flag and retry the call: */\n    if (fd < 0 && sock_cloexec && errno == EINVAL) {\n        sock_cloexec = 0;\n        fd = socket(ia_family(addr), SOCK_STREAM, ia_proto(addr));\n    }\n#endif\n    if (fd < 0) {\n        set_strerror(sock, ne_errno);\n\treturn -1;\n    }\n    \n#if !defined(NE_USE_POLL) && !defined(WIN32)\n    if (fd > FD_SETSIZE) {\n        ne_close(fd);\n        set_error(sock, _(\"Socket descriptor number exceeds FD_SETSIZE\"));\n        return NE_SOCK_ERROR;\n    }\n#endif\n   \n#if defined(HAVE_FCNTL) && defined(F_GETFD) && defined(F_SETFD) \\\n  && defined(FD_CLOEXEC)\n    /* Set the FD_CLOEXEC bit for the new fd, if the socket was not\n     * created with the CLOEXEC bit already set. */\n    if (!sock_cloexec && (ret = fcntl(fd, F_GETFD)) >= 0) {\n        fcntl(fd, F_SETFD, ret | FD_CLOEXEC);\n        /* ignore failure; not a critical error. */\n    }\n#endif\n\n    if (sock->laddr && (sock->laddr == &dummy_laddr || \n                        ia_family(sock->laddr) == ia_family(addr))) {\n        ret = do_bind(fd, ia_family(addr), sock->laddr, sock->lport);\n        if (ret < 0) {\n            int errnum = ne_errno;\n            ne_close(fd);\n            set_strerror(sock, errnum);\n            return NE_SOCK_ERROR;\n        }\n    }\n\n#if defined(HAVE_SETSOCKOPT) && (defined(TCP_NODELAY) || defined(WIN32))\n    { /* Disable the Nagle algorithm. */\n        int flag = 1;\n        setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof flag);\n    }\n#endif\n    \n    ret = connect_socket(sock, fd, addr, htons(port));\n    if (ret == 0)\n        sock->fd = fd;\n    else\n        ne_close(fd);\n\n    return ret;\n}\n\nne_inet_addr *ne_sock_peer(ne_socket *sock, unsigned int *port)\n{\n    union saun {\n        struct sockaddr sa;\n        struct sockaddr_in sin;\n#if defined(USE_GETADDRINFO) && defined(AF_INET6)\n        struct sockaddr_in6 sin6;\n#endif\n    } saun;\n    socklen_t len = sizeof saun;\n    ne_inet_addr *ia;\n    struct sockaddr *sad = (struct sockaddr *)&saun;\n\n    if (getpeername(sock->fd, sad, &len) != 0) {\n        set_strerror(sock, errno);\n        return NULL;\n    }\n\n#if !defined(USE_GETADDRINFO) || !defined(AF_INET6)\n    if (sad->sa_family != AF_INET) {\n        set_error(sock, _(\"Socket family not supported\"));\n        return NULL;\n    }\n#endif                  \n\n    ia = ne_calloc(sizeof *ia);\n#ifdef USE_GETADDRINFO\n    ia->ai_addr = ne_malloc(len);\n    ia->ai_addrlen = len;\n    memcpy(ia->ai_addr, sad, len);\n    ia->ai_family = saun.sa.sa_family;\n#else\n    memcpy(ia, &saun.sin.sin_addr.s_addr, sizeof *ia);\n#endif    \n\n#if defined(USE_GETADDRINFO) && defined(AF_INET6)\n    *port = ntohs(saun.sa.sa_family == AF_INET ? \n                  saun.sin.sin_port : saun.sin6.sin6_port);\n#else\n    *port = ntohs(saun.sin.sin_port);\n#endif\n\n    return ia;\n}\n\nne_inet_addr *ne_iaddr_make(ne_iaddr_type type, const unsigned char *raw)\n{\n    ne_inet_addr *ia;\n#if !defined(USE_GETADDRINFO)\n    /* fail if IPv6 address is given if IPv6 is not supported. */\n    if (type == ne_iaddr_ipv6)\n\treturn NULL;\n#endif\n    return ne_iaddr_put(ne_calloc(sizeof *ia), type, raw);\n}\n\nne_inet_addr *ne_iaddr_put(ne_inet_addr *ia, ne_iaddr_type type, const unsigned char *raw)\n{\n#ifdef USE_GETADDRINFO\n    if (ia->ai_addr) ne_free(ia->ai_addr);\n    /* ai_protocol and ai_socktype aren't used by connect_socket() so\n     * ignore them here. (for now) */\n    if (type == ne_iaddr_ipv4) {\n\tstruct sockaddr_in *in4 = ne_calloc(sizeof *in4);\n\tia->ai_family = AF_INET;\n\tia->ai_addr = (struct sockaddr *)in4;\n\tia->ai_addrlen = sizeof *in4;\n\tin4->sin_family = AF_INET;\n#ifdef __NetBSD__\n\tin4->sin_len = sizeof *in4;\n#endif\n\tmemcpy(&in4->sin_addr.s_addr, raw, sizeof in4->sin_addr.s_addr);\n    }\n#ifdef AF_INET6\n    else {\n\tstruct sockaddr_in6 *in6 = ne_calloc(sizeof *in6);\n\tia->ai_family = AF_INET6;\n\tia->ai_addr = (struct sockaddr *)in6;\n\tia->ai_addrlen = sizeof *in6;\n\tin6->sin6_family = AF_INET6;\n#ifdef __NetBSD__\n\tin6->sin6_len = sizeof *in6;\n#endif\n\tmemcpy(&in6->sin6_addr, raw, sizeof in6->sin6_addr.s6_addr);\n    }\n#endif\n#else /* !USE_GETADDRINFO */\n    /* fail if IPv6 address is given if IPv6 is not supported. */\n    if (type == ne_iaddr_ipv6)\n        return NULL;\n    memcpy(&ia->s_addr, raw, sizeof ia->s_addr);\n#endif /* USE_GETADDRINFO */\n    return ia;\n}\n\nne_iaddr_type ne_iaddr_typeof(const ne_inet_addr *ia)\n{\n#if defined(USE_GETADDRINFO) && defined(AF_INET6)\n    return ia->ai_family == AF_INET6 ? ne_iaddr_ipv6 : ne_iaddr_ipv4;\n#else\n    return ne_iaddr_ipv4;\n#endif\n}\n\nint ne_iaddr_cmp(const ne_inet_addr *i1, const ne_inet_addr *i2)\n{\n#ifdef USE_GETADDRINFO\n    if (i1->ai_family != i2->ai_family)\n\treturn i2->ai_family - i1->ai_family;\n    if (i1->ai_family == AF_INET) {\n\tstruct sockaddr_in *in1 = SACAST(in, i1->ai_addr), \n\t    *in2 = SACAST(in, i2->ai_addr);\n\treturn memcmp(&in1->sin_addr.s_addr, &in2->sin_addr.s_addr, \n\t\t      sizeof in1->sin_addr.s_addr);\n    } \n#ifdef AF_INET6\n    else if (i1->ai_family == AF_INET6) {\n\tstruct sockaddr_in6 *in1 = SACAST(in6, i1->ai_addr), \n\t    *in2 = SACAST(in6, i2->ai_addr);\n\treturn memcmp(in1->sin6_addr.s6_addr, in2->sin6_addr.s6_addr,\n\t\t      sizeof in1->sin6_addr.s6_addr);\n    } \n#endif /* AF_INET6 */\n    else\n\treturn -1;\n#else\n    return memcmp(&i1->s_addr, &i2->s_addr, sizeof i1->s_addr);\n#endif /* USE_GETADDRINFO */\n}\n\nvoid ne_iaddr_free(ne_inet_addr *addr)\n{\n#ifdef USE_GETADDRINFO\n    ne_free(addr->ai_addr);\n#endif\n    ne_free(addr);\n}\n\nint ne_sock_accept(ne_socket *sock, int listener) \n{\n    int fd = accept(listener, NULL, NULL);\n\n    if (fd < 0) {\n        set_strerror(sock, ne_errno);\n        return -1;\n    }\n\n    sock->fd = fd;\n    return 0;\n}\n\nint ne_sock_fd(const ne_socket *sock)\n{\n    return sock->fd;\n}\n\nvoid ne_sock_read_timeout(ne_socket *sock, int timeout)\n{\n    sock->rdtimeout = timeout;\n}\n\nvoid ne_sock_connect_timeout(ne_socket *sock, int timeout)\n{\n    sock->cotimeout = timeout;\n}\n\n#ifdef NE_HAVE_SSL\n\n/* Functions common to OpenSSL and GnuTLS: */\nne_ssl_socket *ne__sock_sslsock(ne_socket *sock)\n{\n    return &sock->ssl;\n}\n\nvoid ne__sock_set_verify_err(ne_socket *sock, int failures)\n{\n    static const struct {\n        int bit;\n        const char *str;\n    } reasons[] = {\n        { NE_SSL_NOTYETVALID, N_(\"certificate is not yet valid\") },\n        { NE_SSL_EXPIRED, N_(\"certificate has expired\") },\n        { NE_SSL_IDMISMATCH, N_(\"certificate issued for a different hostname\") },\n        { NE_SSL_UNTRUSTED, N_(\"issuer is not trusted\") },\n        { NE_SSL_BADCHAIN, N_(\"bad certificate chain\") },\n        { NE_SSL_REVOKED, N_(\"certificate has been revoked\") },\n        { 0, NULL }\n    };\n    int n, flag = 0;\n\n    ne_strnzcpy(sock->error, _(\"Server certificate verification failed: \"),\n                sizeof sock->error);\n\n    for (n = 0; reasons[n].bit; n++) {\n        if (failures & reasons[n].bit) {\n            if (flag) strncat(sock->error, \", \", sizeof sock->error - 1);\n            strncat(sock->error, _(reasons[n].str), sizeof sock->error - 1);\n            flag = 1;\n        }\n    }\n}\n\n#ifdef HAVE_GNUTLS\n/* Dumb server session cache implementation for GNUTLS; holds a single\n * session. */\n\n/* Copy datum 'src' to 'dest'. */\nstatic void copy_datum(gnutls_datum_t *dest, gnutls_datum_t *src)\n{\n    dest->size = src->size;\n    dest->data = memcpy(gnutls_malloc(src->size), src->data, src->size);\n}\n\n/* Callback to store a session 'data' with id 'key'. */\nstatic int store_sess(void *userdata, gnutls_datum_t key, gnutls_datum_t data)\n{\n    ne_ssl_context *ctx = userdata;\n\n    if (ctx->cache.server.key.data) { \n        gnutls_free(ctx->cache.server.key.data);\n        gnutls_free(ctx->cache.server.data.data);\n    }\n\n    copy_datum(&ctx->cache.server.key, &key);\n    copy_datum(&ctx->cache.server.data, &data);\n\n    return 0;\n}\n\n/* Returns non-zero if d1 and d2 are the same datum. */\nstatic int match_datum(gnutls_datum_t *d1, gnutls_datum_t *d2)\n{\n    return d1->size == d2->size\n        && memcmp(d1->data, d2->data, d1->size) == 0;\n}\n\n/* Callback to retrieve a session of id 'key'. */\nstatic gnutls_datum_t retrieve_sess(void *userdata, gnutls_datum_t key)\n{\n    ne_ssl_context *ctx = userdata;\n    gnutls_datum_t ret = { NULL, 0 };\n\n    if (match_datum(&ctx->cache.server.key, &key)) {\n        copy_datum(&ret, &ctx->cache.server.data);\n    }\n\n    return ret;\n}\n\n/* Callback to remove a session of id 'key'; stub needed but\n * implementation seems unnecessary. */\nstatic int remove_sess(void *userdata, gnutls_datum_t key)\n{\n    return -1;\n}\n\nstatic int set_priority(ne_socket *sock, ne_ssl_context *ctx)\n{\n    gnutls_set_default_priority(sock_ssl(sock));\n\n#ifdef HAVE_GNUTLS_SET_DEFAULT_PRIORITY_APPEND\n    if (ctx->priority) {\n        const char *pos = NULL;\n\n        NE_DEBUG(NE_DBG_SSL, \"ssl: Using priority string %s\\n\", ctx->priority);\n\n        if (gnutls_set_default_priority_append(sock_ssl(sock), ctx->priority, &pos, 0) != GNUTLS_E_SUCCESS) {\n            ne_snprintf(sock->error, sizeof sock->error,\n                        _(\"SSL error: failed to set priority string at '%s'\"), pos);\n            return NE_SOCK_ERROR;\n        }\n    }\n#endif\n\n    return 0;\n}\n\n#endif\n\nint ne_sock_accept_ssl(ne_socket *sock, ne_ssl_context *ctx)\n{\n    int ret;\n#if defined(HAVE_OPENSSL)\n    SSL *ssl = SSL_new(ctx->ctx);\n    \n    SSL_set_fd(ssl, sock->fd);\n\n    sock_ssl(sock) = ssl;\n    ret = SSL_accept(ssl);\n    if (ret != 1) {\n        return error_ossl(sock, ret);\n    }\n\n    if (SSL_session_reused(ssl)) {\n        NE_DEBUG(NE_DBG_SSL, \"ssl: Server reused session.\\n\");\n    }\n#elif defined(HAVE_GNUTLS)\n    unsigned int verify_status;\n    gnutls_session_t ssl;\n\n    gnutls_init(&ssl, GNUTLS_SERVER);\n    sock_ssl(sock) = ssl;\n    if (set_priority(sock, ctx)) {\n        return NE_SOCK_ERROR;\n    }\n\n    gnutls_credentials_set(ssl, GNUTLS_CRD_CERTIFICATE, ctx->cred);\n\n    /* Set up dummy session cache. */\n    gnutls_db_set_store_function(ssl, store_sess);\n    gnutls_db_set_retrieve_function(ssl, retrieve_sess);    \n    gnutls_db_set_remove_function(ssl, remove_sess);    \n    gnutls_db_set_ptr(ssl, ctx);\n\n    if (ctx->verify)\n        gnutls_certificate_server_set_request(ssl, GNUTLS_CERT_REQUIRE);\n\n    gnutls_transport_set_ptr(sock_ssl(sock), (gnutls_transport_ptr_t)(long)sock->fd);\n    ret = gnutls_handshake(ssl);\n    if (ret < 0) {\n        return error_gnutls(sock, ret);\n    }\n    if (ctx->verify && (gnutls_certificate_verify_peers2(ssl, &verify_status) || verify_status)) {\n        set_error(sock, _(\"Client certificate verification failed\"));\n        return NE_SOCK_ERROR;\n    }\n#endif\n    sock->ops = &iofns_ssl;\n    return 0;\n}\n\nint ne_sock_connect_ssl(ne_socket *sock, ne_ssl_context *ctx, void *userdata)\n{\n    return ne_sock_handshake(sock, ctx, NULL, 0);\n}\n\nint ne_sock_handshake(ne_socket *sock, ne_ssl_context *ctx,\n                      const char *hostname, unsigned int flags)\n{\n    int ret;\n\n#if defined(HAVE_OPENSSL)\n    SSL *ssl;\n\n    if (seed_ssl_prng()) {\n\tset_error(sock, _(\"SSL disabled due to lack of entropy\"));\n\treturn NE_SOCK_ERROR;\n    }\n\n    sock_ssl(sock) = ssl = SSL_new(ctx->ctx);\n    if (!ssl) {\n\tset_error(sock, _(\"Could not create SSL structure\"));\n\treturn NE_SOCK_ERROR;\n    }\n    \n    SSL_set_app_data(ssl, &sock->ssl);\n#if OPENSSL_VERSION_NUMBER < 0x10101000L\n    SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);\n#else\n    SSL_clear_mode(ssl, SSL_MODE_AUTO_RETRY);\n#endif    \n    SSL_set_fd(ssl, sock->fd);\n    sock->ops = &iofns_ssl;\n\n#ifdef SSL_set_tlsext_host_name\n    if (hostname) {\n        /* Try to enable SNI, but ignore failure (should only fail for\n         * >255 char hostnames, which are probably not legal\n         * anyway).  */\n        if (SSL_set_tlsext_host_name(ssl, hostname) != 1) {\n            ERR_clear_error();\n        }\n    }\n#endif\n\n    if (ctx->sess) {\n        ret = SSL_set_session(ssl, ctx->sess);\n        NE_DEBUG(NE_DBG_SSL, \"sslsess: Using cached session: set_session = %d.\\n\", ret);\n    }\n\n    ret = SSL_connect(ssl);\n    if (ret != 1) {\n\terror_ossl(sock, ret);\n\tSSL_free(ssl);\n\tsock_ssl(sock) = NULL;\n\treturn NE_SOCK_ERROR;\n    }\n#elif defined(HAVE_GNUTLS)\n    sock->ssl.context = ctx;\n\n    /* DH and RSA params are set in ne_ssl_context_create */\n    gnutls_init(&sock_ssl(sock), GNUTLS_CLIENT);\n\n    if (set_priority(sock, ctx)) {\n        return NE_SOCK_ERROR;\n    }\n\n    gnutls_session_set_ptr(sock_ssl(sock), sock);\n    gnutls_credentials_set(sock_ssl(sock), GNUTLS_CRD_CERTIFICATE, ctx->cred);\n\n    if (hostname) {\n        gnutls_server_name_set(sock_ssl(sock), GNUTLS_NAME_DNS, hostname,\n                               strlen(hostname));\n    }                               \n\n    gnutls_transport_set_ptr(sock_ssl(sock), (gnutls_transport_ptr_t)(long)sock->fd);\n\n    if (ctx->cache.client.data) {\n#if defined(HAVE_GNUTLS_SESSION_GET_DATA2)\n        gnutls_session_set_data(sock_ssl(sock), \n                                ctx->cache.client.data, \n                                ctx->cache.client.size);\n#else\n        gnutls_session_set_data(sock_ssl(sock), \n                                ctx->cache.client.data, \n                                ctx->cache.client.len);\n#endif\n    }\n    sock->ops = &iofns_ssl;\n\n    do {\n        ret = gnutls_handshake(sock_ssl(sock));\n    } while (RETRY_GNUTLS(sock, ret));\n    if (ret < 0) {\n\terror_gnutls(sock, ret);\n        return NE_SOCK_ERROR;\n    }\n\n    if (!gnutls_session_is_resumed(sock_ssl(sock))) {\n        /* New session.  The old method of using the _get_data\n         * function seems to be broken with 1.3.0 and later*/\n#if defined(HAVE_GNUTLS_SESSION_GET_DATA2)\n        gnutls_session_get_data2(sock_ssl(sock), &ctx->cache.client);\n#else\n        ctx->cache.client.len = 0;\n        if (gnutls_session_get_data(sock_ssl(sock), NULL, \n                                    &ctx->cache.client.len) == 0) {\n            ctx->cache.client.data = ne_malloc(ctx->cache.client.len);\n            gnutls_session_get_data(sock_ssl(sock), ctx->cache.client.data, \n                                    &ctx->cache.client.len);\n        }\n#endif\n    }\n#endif\n    return 0;\n}\n\n#endif\n\nint ne_sock_sessid(ne_socket *sock, unsigned char *buf, size_t *buflen)\n{\n#ifdef NE_HAVE_SSL\n#ifdef HAVE_GNUTLS\n    if (sock_ssl(sock)) {\n        return gnutls_session_get_id(sock_ssl(sock), buf, buflen);\n    } else {\n        return -1;\n    }\n#else\n    SSL_SESSION *sess;\n    const unsigned char *idbuf;\n    unsigned int idlen;\n\n    if (!sock_ssl(sock)) {\n        return -1;\n    }\n\n    sess = SSL_get0_session(sock_ssl(sock));\n\n    idbuf = SSL_SESSION_get_id(sess, &idlen);\n    if (!buf) {\n        *buflen = idlen;\n        return 0;\n    }\n\n    if (*buflen < idlen) {\n        return -1;\n    }\n\n    *buflen = idlen;\n    memcpy(buf, idbuf, idlen);\n    return 0;\n#endif\n#else\n    return -1;\n#endif\n}\n\nchar *ne_sock_cipher(ne_socket *sock)\n{\n#ifdef NE_HAVE_SSL\n    if (sock_ssl(sock)) {\n#ifdef HAVE_OPENSSL\n        const SSL_CIPHER *ciph = SSL_get_current_cipher(sock_ssl(sock));\n#ifdef HAVE_SSL_CIPHER_STANDARD_NAME\n        const char *name = SSL_CIPHER_standard_name(ciph);\n#else\n        const char *name = SSL_CIPHER_get_name(ciph);\n#endif\n#elif defined(HAVE_GNUTLS_CIPHERSUITE_GET)\n        const char *name = gnutls_ciphersuite_get(sock_ssl(sock));\n#else\n        const char *name = gnutls_cipher_get_name(gnutls_cipher_get(sock_ssl(sock)));\n#endif\n        return ne_strdup(name);\n    }\n    else \n#endif /* NE_HAVE_SSL */\n    {\n        return NULL;\n    }    \n}\n\nenum ne_ssl_protocol ne_sock_getproto(ne_socket *sock)\n{\n#ifdef NE_HAVE_SSL\n    if (sock_ssl(sock)) {\n#if defined(HAVE_OPENSSL)\n        switch (SSL_version(sock_ssl(sock))) {\n        case SSL3_VERSION:\n            return NE_SSL_PROTO_SSL_3;\n        case TLS1_VERSION:\n            return NE_SSL_PROTO_TLS_1_0;\n        case TLS1_1_VERSION:\n            return NE_SSL_PROTO_TLS_1_1;\n#ifdef TLS1_2_VERSION\n        case TLS1_2_VERSION:\n            return NE_SSL_PROTO_TLS_1_2;\n#endif\n#ifdef TLS1_3_VERSION\n        case TLS1_3_VERSION:\n            return NE_SSL_PROTO_TLS_1_3;\n#endif\n        default:\n            break;\n        }\n#elif defined(HAVE_GNUTLS)\n        switch (gnutls_protocol_get_version(sock_ssl(sock))) {\n        case GNUTLS_SSL3:\n            return NE_SSL_PROTO_SSL_3;\n        case GNUTLS_TLS1_0:\n            return NE_SSL_PROTO_TLS_1_0;\n        case GNUTLS_TLS1_1:\n            return NE_SSL_PROTO_TLS_1_1;\n        case GNUTLS_TLS1_2:\n            return NE_SSL_PROTO_TLS_1_2;\n        case GNUTLS_TLS1_3:\n            return NE_SSL_PROTO_TLS_1_3;\n        default:\n            break;\n        }\n#endif\n    }\n#endif /* NE_HAVE_SSL */\n\n    return NE_SSL_PROTO_UNSPEC;\n}\n\nne_ssl_certificate *ne_sock_getcert(ne_socket *sock, ne_ssl_context *ctx)\n{\n    ne_ssl_certificate *ret = NULL;\n#if defined(HAVE_OPENSSL)\n    STACK_OF(X509) *chain = SSL_get_peer_cert_chain(sock_ssl(sock));\n\n    if (chain == NULL || sk_X509_num(chain) == 0) {\n        set_error(sock, _(\"SSL server did not present certificate\"));\n        return NULL;\n    }\n\n    ret = ne__ssl_make_chain(chain);\n#elif defined(HAVE_GNUTLS)\n    ret = ne__ssl_make_chain(sock_ssl(sock), ctx->cred);\n#endif\n    return ret;\n}\n\nconst char *ne_sock_error(const ne_socket *sock)\n{\n    return sock->error;\n}\n\nvoid ne_sock_set_error(ne_socket *sock, const char *format, ...)\n{\n    va_list params;\n\n    va_start(params, format);\n    ne_vsnprintf(sock->error, sizeof sock->error, format, params);\n    va_end(params);\n}\n\nint ne_sock_shutdown(ne_socket *sock, unsigned int flags)\n{\n    int ret;\n\n    if (!flags) {\n        set_error(sock, _(\"Missing flags for socket shutdown\"));\n        return NE_SOCK_ERROR;\n    }\n\n#if defined(HAVE_OPENSSL)\n    if (sock_ssl(sock)) {\n        int state = SSL_get_shutdown(sock_ssl(sock));\n\n        NE_DEBUG(NE_DBG_SSL, \"ssl: Shutdown state: %ssent | %sreceived.\\n\",\n                 (state & SSL_SENT_SHUTDOWN) ? \"\" : \"not \",\n                 (state & SSL_RECEIVED_SHUTDOWN) ? \"\" : \"not \");\n\n        if ((flags == NE_SOCK_BOTH || flags == NE_SOCK_SEND)\n            && (state & SSL_SENT_SHUTDOWN) == 0) {\n            NE_DEBUG(NE_DBG_SSL, \"ssl: Sending closure.\\n\");\n            ret = SSL_shutdown(sock_ssl(sock));\n\n            if (ret == 0) {\n                set_error(sock, _(\"Incomplete TLS closure\"));\n                return NE_SOCK_RETRY;\n            }\n            else if (ret != 1) {\n                return error_ossl(sock, ret);\n            }\n        }\n\n\tif (flags == NE_SOCK_RECV || flags == NE_SOCK_BOTH) {\n\t    /* Returns whether the receive side is shutdown or not yet. */\n\t    if ((state & SSL_RECEIVED_SHUTDOWN) == 0) {\n\t\tset_error(sock, _(\"Incomplete TLS closure\"));\n\t\treturn NE_SOCK_RETRY;\n\t    }\n\n            /* For recv-only shutdown, must not complete TCP-level\n             * shutdown until the TLS shutdown is complete. */\n            if (flags == NE_SOCK_RECV) {\n                return 0;\n            }\n\t}\n    }\n#elif defined(HAVE_GNUTLS)\n    if (sock_ssl(sock)) {\n        if (flags == NE_SOCK_RECV) {\n            /* unclear how to handle */\n            set_error(sock, _(\"Incomplete TLS closure\"));\n            return NE_SOCK_RETRY;\n        }\n\n        ret = gnutls_bye(sock_ssl(sock),\n                         flags == NE_SOCK_SEND ? GNUTLS_SHUT_WR : GNUTLS_SHUT_RDWR);\n        if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {\n            return NE_SOCK_RETRY;\n        }\n    }\n#endif\n\n#ifdef _WIN32\n    int how = flags == NE_SOCK_RECV ? SD_RECEIVE : (flags == NE_SOCK_SEND ? SD_SEND : SD_BOTH);\n#else\n    int how = flags == NE_SOCK_RECV ? SHUT_RD : (flags == NE_SOCK_SEND ? SHUT_WR : SHUT_RDWR);\n#endif\n    ret = shutdown(sock->fd, how);\n    if (ret < 0) {\n\tint errnum = ne_errno;\n\tset_strerror(sock, errnum);\n\treturn MAP_ERR(errnum);\n    }\n\n    return ret;\n}\n\nint ne_sock_close(ne_socket *sock)\n{\n    int ret;\n\n    if (sock->fd != -1) {\n        /* Ignore errors. */\n        (void) ne_sock_shutdown(sock, NE_SOCK_SEND);\n    }\n\n#if defined(HAVE_OPENSSL)\n    if (sock_ssl(sock)) {\n        SSL_free(sock_ssl(sock));\n    }\n#elif defined(HAVE_GNUTLS)\n    if (sock_ssl(sock)) {\n        gnutls_deinit(sock_ssl(sock));\n    }\n#endif\n\n    ret = sock->fd < 0 ? 0 : ne_close(sock->fd);\n\n    ne_free(sock);\n    return ret;\n}\n"
  },
  {
    "path": "src/ne_socket.h",
    "content": "/* \n   socket handling interface\n   Copyright (C) 1999-2021, Joe Orton <joe@manyfish.co.uk>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n   \n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n\n#ifndef NE_SOCKET_H\n#define NE_SOCKET_H\n\n#include <sys/types.h>\n\n#ifdef WIN32\n#include <stdlib.h> /* for size_t */\n#endif\n\n#include \"ne_defs.h\"\n#include \"ne_ssl.h\" /* for ne_ssl_context */\n\nNE_BEGIN_DECLS\n\n#define NE_SOCK_ERROR (-1)\n/* Read/Write timed out */\n#define NE_SOCK_TIMEOUT (-2)\n/* Socket was closed */\n#define NE_SOCK_CLOSED (-3)\n/* Connection was reset (e.g. server crashed) */\n#define NE_SOCK_RESET (-4)\n/* Secure connection was closed without proper SSL shutdown. */\n#define NE_SOCK_TRUNC (-5)\n/* Retry operation later. */\n#define NE_SOCK_RETRY (-6)\n\n/* ne_socket represents a TCP socket. */\ntypedef struct ne_socket_s ne_socket;\n\n/* ne_sock_addr represents an address object. */\ntypedef struct ne_sock_addr_s ne_sock_addr;\n\n#ifndef NE_INET_ADDR_DEFINED\ntypedef struct ne_inet_addr_s ne_inet_addr;\n#endif\n\n/* Perform process-global initialization of any libraries in use.\n * Returns non-zero on error. */\nint ne_sock_init(void);\n\n/* Perform process-global shutdown of any libraries in use.  This\n * function only has effect when it has been called an equal number of\n * times to ne_sock_init() for the process. */\nvoid ne_sock_exit(void);\n\n#define NE_ADDR_CANON (0x01)\n/* Resolve the given hostname. Hex string IPv6 addresses (e.g. `::1')\n * may be enclosed in brackets (e.g. `[::1]').  'flags' should be\n * zero, or if NE_ADDR_CANON is passed, the canonical name for the\n * hostname will be determined. */\nne_sock_addr *ne_addr_resolve(const char *hostname, int flags);\n\n/* Returns zero if name resolution was successful, non-zero on\n * error. */\nint ne_addr_result(const ne_sock_addr *addr);\n\n/* Returns the first network address associated with the 'addr'\n * object.  Undefined behaviour if ne_addr_result returns non-zero for\n * 'addr'; otherwise, never returns NULL.  */\nconst ne_inet_addr *ne_addr_first(ne_sock_addr *addr);\n\n/* Returns the next network address associated with the 'addr' object,\n * or NULL if there are no more. */\nconst ne_inet_addr *ne_addr_next(ne_sock_addr *addr);\n\n/* NB: the pointers returned by ne_addr_first and ne_addr_next are\n * valid until ne_addr_destroy is called for the corresponding\n * ne_sock_addr object.  They must not be passed to ne_iaddr_free. */\n\n/* If name resolution fails, copies the error string into 'buffer',\n * which is of size 'bufsiz'.  'buffer' is returned. */\nchar *ne_addr_error(const ne_sock_addr *addr, char *buffer, size_t bufsiz);\n\n/* Returns the canonical name of the host as a NUL-terminated string,\n * if NE_ADDR_CANON was used, and name resolution was successful.\n * Otherwise, returns NULL. */\nconst char *ne_addr_canonical(const ne_sock_addr *addr);\n\n/* Destroys an address object created by ne_addr_resolve. */\nvoid ne_addr_destroy(ne_sock_addr *addr);\n\n/* Network address type; IPv4 or IPv6 */\ntypedef enum {\n    ne_iaddr_ipv4 = 0,\n    ne_iaddr_ipv6\n} ne_iaddr_type;\n\n/* Create a network address object from raw byte representation (in\n * network byte order) of given type.  'raw' must be four bytes for an\n * IPv4 address, 16 bytes for an IPv6 address.  May return NULL if\n * address type is not supported. */\nne_inet_addr *ne_iaddr_make(ne_iaddr_type type, const unsigned char *raw);\n\n/* Change an existing network address object to a new raw byte\n * representation of given 'type'. The raw data must be of length 4\n * bytes for an IPv4 address, or 16 bytes for an IPv6 address. Returns\n * NULL if the address type is not supported, or else 'ia'. */\nne_inet_addr *ne_iaddr_put(ne_inet_addr *ia, ne_iaddr_type type,\n                           const unsigned char *raw);\n\n/* Compare two network address objects i1 and i2; returns zero if they\n * are equivalent or non-zero otherwise. For an IPv6 literal, the\n * scope is ignored by this function if set, so must be compared\n * seperately if required. */\nint ne_iaddr_cmp(const ne_inet_addr *i1, const ne_inet_addr *i2);\n\n/* Return the type of the given network address object. */\nne_iaddr_type ne_iaddr_typeof(const ne_inet_addr *ia);\n\n/* Print the string representation of network address 'ia' into the\n * buffer 'buffer', which is of length 'bufsiz'.  Returns 'buffer'. */\nchar *ne_iaddr_print(const ne_inet_addr *ia, char *buffer, size_t bufsiz);\n\n/* Dump the raw byte representation (in network byte order) of address\n * 'ia' into the buffer 'buffer', which must be of a suitable length\n * (4 bytes for an IPv4 address, 16 bytes for an IPv6 address).\n * Returns 'buffer'. */\nunsigned char *ne_iaddr_raw(const ne_inet_addr *ia, unsigned char *buffer);\n\n/* Perform the reverse name lookup on network address 'ia', placing\n * the returned name in the 'buf' buffer (of length 'bufsiz') if\n * successful.  Returns zero on success, or non-zero on error. */\nint ne_iaddr_reverse(const ne_inet_addr *ia, char *buf, size_t bufsiz);\n\n/* Convert network address string 'addr' (for example, \"127.0.0.1\")\n * into a network address object.  Returns NULL on parse error.  If\n * non-NULL, return value must be freed using ne_iaddr_free. */\nne_inet_addr *ne_iaddr_parse(const char *addr, ne_iaddr_type type);\n\n/* Set the scope_id for an IPv6 address from 'scope'. */\nint ne_iaddr_set_scope(ne_inet_addr *ia, const char *scope);\n\n/* Returns the scope_id for an IPv6 address. */\nchar *ne_iaddr_get_scope(const ne_inet_addr *ia);\n\n/* Destroy a network address object created using ne_iaddr_make or\n * ne_iaddr_parse. */\nvoid ne_iaddr_free(ne_inet_addr *addr);\n\n/* Create a socket object; returns NULL on error. */\nne_socket *ne_sock_create(void);\n\n/* Specify an address to which the local end of the socket will be\n * bound during a subsequent ne_sock_connect() call.  If the address\n * passed to ne_sock_connect() is of a different type (family) to\n * 'addr', 'addr' is ignored.  Either 'addr' may be NULL, to use the\n * given port with unspecified address, or 'port' may be 0, to use the\n * given address with an unspecified port.\n *\n * (Note: This function is not equivalent to a BSD socket bind(), it\n * only takes effect during the _connect() call). */\nvoid ne_sock_prebind(ne_socket *sock, const ne_inet_addr *addr,\n                     unsigned int port);\n\n/* Connect the socket to server at address 'addr' on port 'port'.\n * Returns zero on success, NE_SOCK_TIMEOUT if a timeout occurs when a\n * non-zero connect timeout is configured (and is supported), or\n * NE_SOCK_ERROR on failure.  */\nint ne_sock_connect(ne_socket *sock, const ne_inet_addr *addr, \n                    unsigned int port);\n\n/* Read up to 'count' bytes from socket into 'buffer'.  Returns:\n *   NE_SOCK_* on error,\n *   >0 length of data read into buffer (may be less than 'count')\n */\nssize_t ne_sock_read(ne_socket *sock, char *buffer, size_t count);\n\n/* Read up to 'count' bytes into 'buffer', leaving the data available\n * in the socket buffer to be returned by a subsequent call to\n * ne_sock_read or ne_sock_peek. Returns:\n *   NE_SOCK_* on error,\n *   >0 length of data read into buffer.\n */\nssize_t ne_sock_peek(ne_socket *sock, char *buffer, size_t count);\n\n/* Block for up to 'n' seconds until data becomes available for reading\n * from the socket. Returns:\n *  NE_SOCK_* on error,\n *  NE_SOCK_TIMEOUT if no data arrives in 'n' seconds,\n *  0 if data arrived on the socket.\n */\nint ne_sock_block(ne_socket *sock, int n);\n\n/* Write 'count' bytes of 'data' to the socket.  Guarantees to either\n * write all the bytes or to fail.  Returns 0 on success, or NE_SOCK_*\n * on error. */\nint ne_sock_fullwrite(ne_socket *sock, const char *data, size_t count); \n\n/* I/O vector. */\nstruct ne_iovec {\n    void *base;\n    size_t len;\n};\n\n/* Writes 'count' blocks described by 'vector' to the socket.\n * Guarantees to either write all the bytes or to fail.  Count must be\n * greater than zero and smaller than the system-defined maximum\n * vector limit.  Returns 0 on success, or NE_SOCK_* on error. */\nint ne_sock_fullwritev(ne_socket *sock, const struct ne_iovec *vector,\n                       int count); \n\n/* Read an LF-terminated line into 'buffer', and NUL-terminate it.\n * At most 'len' bytes are read (including the NUL terminator).\n * Returns:\n * NE_SOCK_* on error,\n * >0 number of bytes read (excluding NUL terminator)\n */\nssize_t ne_sock_readline(ne_socket *sock, char *buffer, size_t len);\n\n/* Read exactly 'len' bytes into buffer, or fail; returns 0 on\n * success, NE_SOCK_* on error. */\nssize_t ne_sock_fullread(ne_socket *sock, char *buffer, size_t len);\n\n/* Accepts a connection from listening socket 'fd' and places the\n * socket in 'sock'.  Returns zero on success or -1 on failure. */\nint ne_sock_accept(ne_socket *sock, int fd);\n\n/* Returns the file descriptor used for socket 'sock'. */\nint ne_sock_fd(const ne_socket *sock);\n\n/* Return address of peer, or NULL on error.  The returned address\n * must be destroyed by caller using ne_iaddr_free. */\nne_inet_addr *ne_sock_peer(ne_socket *sock, unsigned int *port);\n\n/* Flags for ne_sock_shutdown():  */\n#define NE_SOCK_RECV (1)\n#define NE_SOCK_SEND (2)\n#define NE_SOCK_BOTH (3)\n\n/* Shut down the socket in one or both directions, without destroying\n * the socket object.  Flags must be one of NE_SOCK_RECV/SEND/BOTH.\n * For a non-TLS socket, performs the directional shutdown according\n * to flags.\n * For a TLS socket:\n * - if flags are NE_SOCK_SEND or NE_SOCK_BOTH, sends the TLS\n *   close_notify.  Returns NE_SOCK_RETRY if the TLS connection has\n *   not been closed by the peer.\n * - if flags are NE_SOCK_RECV, returns NE_SOCK_RETRY if the \n *   TLS close_notify has not been closed by the peer.\n * In NE_SOCK_SEND or NE_SOCK_BOTH is specified, and the bidirectional\n * TLS shutdown has completed, the TCP shutdown will also be completed \n * as for a non-TLS socket. \n*/\nint ne_sock_shutdown(ne_socket *sock, unsigned int flags);\n\n/* Close the socket if it is open, and destroy the socket object.  If\n * SSL is in use for the socket, a closure alert is sent to initiate a\n * clean shutdown, but this function does not wait for the peer's\n * response.  Returns zero on success, or non-zero on failure. */\nint ne_sock_close(ne_socket *sock);\n\n/* Return current error string for socket. */\nconst char *ne_sock_error(const ne_socket *sock);\n\n/* Set the error string for the socket; takes printf-like format\n * string. */\nvoid ne_sock_set_error(ne_socket *sock, const char *format, ...)\n    ne_attribute((format (printf, 2, 3)));\n\n/* Set read timeout for socket, in seconds; must be a non-zero\n * positive integer. */\nvoid ne_sock_read_timeout(ne_socket *sock, int timeout);\n\n/* Set connect timeout for socket, in seconds; must be a positive\n * integer.  If a timeout of 'zero' is used then then no explicit\n * timeout handling will be used for ne_sock_connect(), and the\n * connect call will only timeout as dictated by the TCP stack. */\nvoid ne_sock_connect_timeout(ne_socket *sock, int timeout);\n\n/* Negotiate an SSL connection on socket as an SSL server, using given\n * SSL context. */\nint ne_sock_accept_ssl(ne_socket *sock, ne_ssl_context *ctx);\n\n/* Deprecated interface for initiating an SSL handshake, use\n * ne_sock_handshake() instead. */\nint ne_sock_connect_ssl(ne_socket *sock, ne_ssl_context *ctx,\n                        void *userdata);\n\n/* Initiate an SSL handshake with SSL context 'ctx', using SNI hint\n * 'hostname' (which may be NULL). 'flags' must be 0. */\nint ne_sock_handshake(ne_socket *sock, ne_ssl_context *ctx,\n                      const char *hostname, unsigned int flags);\n\n/* Retrieve the session ID of the current SSL session.  If 'buf' is\n * non-NULL, on success, copies at most *buflen bytes to 'buf' and\n * sets *buflen to the exact number of bytes copied.  If 'buf' is\n * NULL, on success, sets *buflen to the length of the session ID.\n * Returns zero on success, non-zero on error. */\nint ne_sock_sessid(ne_socket *sock, unsigned char *buf, size_t *buflen);\n\n/* Return human-readable name of SSL/TLS cipher used for connection,\n * or NULL if none.  The format of this string is not intended to be\n * fixed or parseable, but is informational only.  Return value is\n * NUL-terminated malloc-allocated string if not NULL, which must be\n * freed by the caller. */\nchar *ne_sock_cipher(ne_socket *sock);\n\n/* Return the SSL/TLS protocol version used for socket 'sock', or\n * NE_SSL_PROTO_UNSPEC if SSL/TLS is not in use for the socket. */\nenum ne_ssl_protocol ne_sock_getproto(ne_socket *sock);\n\n/* Return the server certificate for the socket. */\nne_ssl_certificate *ne_sock_getcert(ne_socket *sock, ne_ssl_context *ctx);\n\n/* Check the identity of a server certificate against the hostname or\n * address used to establish the connection, following rules specified\n * by RFC 2818 and RFC 3280.  Either hostname or address can be\n * non-NULL; whichever was used to identify the server when\n * establishing the SSL connection. If both are NULL, matching\n * will fail but the *identity output parameter will still be set.\n *\n * Returns zero if identity matches; 1 if identity does not match, or\n * <0 if the certificate had no identity.  If 'identity' is non-NULL,\n * the malloc-allocated identity is stored in *identity. */\nint ne_ssl_check_certificate(ne_ssl_context *ctx, ne_socket *sock,\n                             const char *hostname,\n                             const ne_inet_addr *address,\n                             const ne_ssl_certificate *cert,\n                             unsigned int flags, int *failures);\n\n/* SOCKS proxy protocol version: */\nenum ne_sock_sversion {\n    NE_SOCK_SOCKSV4 = 0,\n    NE_SOCK_SOCKSV4A,\n    NE_SOCK_SOCKSV5\n};\n\n/* Given a socket 'sock' which is connected to a SOCKS proxy, initiate\n * a connection to a destination server using that proxy, specified\n * either by network address or hostname, at given port 'port'.\n *\n * If 'vers' is NE_SOCKS_V4, addr must be an IPv4 address; hostname\n * and password are ignored; username must be non-NULL.\n *\n * If 'vers' is NE_SOCKS_V4A, hostname must be non-NULL; addr is\n * ignored; password is ignored; username must be non-NULL.\n *\n * If 'vers' is NE_SOCKS_V5, addr may be NULL, in which case hostname\n * must be non-NULL.  addr if non-NULL may be an IPv4 or IPv6 address;\n * username may be NULL, in which case password is ignored.  If\n * username is non-NULL password must also be non-NULL.\n *\n * Returns 0 on success, or NE_SOCK_* on failure - in which case, the\n * socket error string is set.  On failure, the socket must be closed\n * by the caller.\n */\nint ne_sock_proxy(ne_socket *sock, enum ne_sock_sversion vers,\n                  const ne_inet_addr *addr, const char *hostname, \n                  unsigned int port,\n                  const char *username, const char *password);\n\nNE_END_DECLS\n\n#endif /* NE_SOCKET_H */\n"
  },
  {
    "path": "src/ne_socks.c",
    "content": "/*\n   SOCKS proxy support for neon\n   Copyright (C) 2021, Joe Orton <joe@manyfish.co.uk>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n\n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n*/\n\n#include \"config.h\"\n\n#include \"ne_internal.h\"\n#include \"ne_string.h\"\n#include \"ne_socket.h\"\n#include \"ne_utils.h\"\n\n#include <string.h>\n\n/* SOCKS protocol reference:\n   v4:  http://www.ufasoft.com/doc/socks4_protocol.htm\n   v4a  http://www.smartftp.com/Products/SmartFTP/RFC/socks4a.protocol\n   v5:  http://tools.ietf.org/html/rfc1928\n   ...v5 auth: http://tools.ietf.org/html/rfc1929\n*/\n\n#define V5_REPLY_OK 0\n#define V5_REPLY_FAIL 1\n#define V5_REPLY_DISALLOW 2\n#define V5_REPLY_NET_UNREACH 3\n#define V5_REPLY_HOST_UNREACH 4\n#define V5_REPLY_CONN_REFUSED 5\n#define V5_REPLY_TTL_EXPIRED 6\n#define V5_REPLY_CMD_UNSUPPORTED 7\n#define V5_REPLY_TYPE_UNSUPPORTED 8\n\n#define V5_VERSION   0x05\n#define V5_ADDR_IPV4 0x01\n#define V5_ADDR_FQDN 0x03\n#define V5_ADDR_IPV6 0x04\n\n#define V5_CMD_CONNECT 0x01\n\n#define V5_AUTH_NONE   0x00\n#define V5_AUTH_USER   0x02\n#define V5_AUTH_NOMETH 0xFF\n\n/* Fail with given V5 error code in given context. */\nstatic int v5fail(ne_socket *sock, unsigned int code, const char *context)\n{\n    const char *err;\n\n    switch (code) {\n    case V5_REPLY_FAIL:\n        err = _(\"failure\");\n        break;\n    case V5_REPLY_DISALLOW:\n        err = _(\"connection not permitted\"); \n        break;\n    case V5_REPLY_NET_UNREACH:\n        err = _(\"network unreachable\");\n        break;\n    case V5_REPLY_HOST_UNREACH: \n        err = _(\"host unreachable\");\n        break;\n    case V5_REPLY_TTL_EXPIRED:\n        err = _(\"TTL expired\");\n        break;\n    case V5_REPLY_CMD_UNSUPPORTED:\n        err = _(\"command not supported\");\n        break;\n    case V5_REPLY_TYPE_UNSUPPORTED: \n        err = _(\"address type not supported\");\n        break;\n    default:\n        ne_sock_set_error(sock, _(\"%s: unrecognized error (%u)\"), context, code);\n        return NE_SOCK_ERROR;\n    }\n    \n    ne_sock_set_error(sock, \"%s: %s\", context, err);\n    return NE_SOCK_ERROR;\n}\n\n/* Fail with given error string. */\nstatic int fail(ne_socket *sock, const char *error)\n{\n    ne_sock_set_error(sock, \"%s\", error);\n    return NE_SOCK_ERROR;\n}\n\n/* Fail with given NE_SOCK_* error code and given context. */\nstatic int sofail(ne_socket *sock, ssize_t ret, const char *context)\n{\n    char *err = ne_strdup(ne_sock_error(sock));\n    ne_sock_set_error(sock, \"%s: %s\", context, err);\n    ne_free(err);\n    return NE_SOCK_ERROR;\n}\n\n/* SOCKSv5 proxy. */\nstatic int v5_proxy(ne_socket *sock, const ne_inet_addr *addr,\n                    const char *hostname, unsigned int port,\n                    const char *username, const char *password)\n{\n    unsigned char msg[1024], *p;\n    unsigned int len;\n    int ret;\n    ssize_t n;\n\n    p = msg;\n    *p++ = V5_VERSION;\n    *p++ = 2; /* Two supported auth protocols; none and user. */\n    *p++ = V5_AUTH_NONE;\n    *p++ = V5_AUTH_USER;\n\n    ret = ne_sock_fullwrite(sock, (char *)msg, p - msg);\n    if (ret) {\n        return sofail(sock, ret, _(\"Could not send message to proxy\"));\n    }\n\n    n = ne_sock_fullread(sock, (char *)msg, 2);\n    if (n) {\n        return sofail(sock, ret, _(\"Could not read initial response from proxy\"));\n    }\n    else if (msg[0] != V5_VERSION) {\n        return fail(sock, _(\"Invalid version in proxy response\"));\n    }\n    \n    /* Authenticate, if necessary. */\n    switch (msg[1]) {\n    case V5_AUTH_NONE:\n        break;\n    case V5_AUTH_USER:\n        p = msg;\n        *p++ = 0x01;\n        len = strlen(username) & 0xff;\n        *p++ = len;\n        memcpy(p, username, len);\n        p += len;\n        len = strlen(password) & 0xff;\n        *p++ = len;\n        memcpy(p, password, len);\n        p += len;\n\n        ret = ne_sock_fullwrite(sock, (char *)msg, p - msg);\n        if (ret) {\n            return sofail(sock, ret, _(\"Could not send login message\"));\n        }\n        \n        n = ne_sock_fullread(sock, (char *)msg, 2);\n        if (n) {\n            return sofail(sock, ret, _(\"Could not read login reply\"));\n        }\n        else if (msg[0] != 1) {\n            return fail(sock, _(\"Invalid version in login reply\"));\n        }\n        else if (msg[1] != 0) {\n            return fail(sock, _(\"Authentication failed\"));\n        }\n        break;\n    case V5_AUTH_NOMETH:\n        return fail(sock, _(\"No acceptable authentication method\"));\n    default:\n        return fail(sock, _(\"Unexpected authentication method chosen\"));\n    }\n    \n    /* Send the CONNECT command. */\n    p = msg;\n    *p++ = V5_VERSION;\n    *p++ = V5_CMD_CONNECT;\n    *p++ = 0; /* reserved */\n    if (addr) {\n        unsigned char raw[16];\n\n        if (ne_iaddr_typeof(addr) == ne_iaddr_ipv4) {\n            len = 4;\n            *p++ = V5_ADDR_IPV4;\n        }\n        else {\n            len = 16;\n            *p++ = V5_ADDR_IPV6;\n        }\n        \n        memcpy(p, ne_iaddr_raw(addr, raw), len);\n        p += len;\n    }\n    else {\n        len = strlen(hostname) & 0xff;\n        *p++ = V5_ADDR_FQDN;\n        *p++ = len;\n        memcpy(p, hostname, len);\n        p += len;\n    }\n\n    *p++ = (port >> 8) & 0xff;\n    *p++ = port & 0xff;\n\n    ret = ne_sock_fullwrite(sock, (char *)msg, p - msg);\n    if (ret) {\n        return sofail(sock, ret, _(\"Could not send connect request\"));\n    }\n\n    n = ne_sock_fullread(sock, (char *)msg, 4);\n    if (n) {\n        return sofail(sock, n, _(\"Could not read connect reply\"));\n    }\n    if (msg[0] != V5_VERSION) {\n        return fail(sock, _(\"Invalid version in connect reply\"));\n    }\n    if (msg[1] != V5_REPLY_OK) {\n        return v5fail(sock, msg[1], _(\"Could not connect\"));\n    }\n    \n    switch (msg[3]) {\n    case V5_ADDR_IPV4:\n        len = 4;\n        break;\n    case V5_ADDR_IPV6:\n        len = 16;\n        break;\n    case V5_ADDR_FQDN:\n        n = ne_sock_read(sock, (char *)msg, 1);\n        if (n != 1) {\n            return sofail(sock, n, \n                            _(\"Could not read FQDN length in connect reply\"));\n        }\n        len = msg[0];\n        break;\n    default:\n        return fail(sock, _(\"Unknown address type in connect reply\"));\n    }\n\n    n = ne_sock_fullread(sock, (char *)msg, len + 2);\n    if (n) {\n        return sofail(sock, n, _(\"Could not read address in connect reply\"));\n    }\n\n    return 0;\n}\n\n#define V4_VERSION 0x04\n#define V4_CMD_STREAM 0x01\n\n#define V4_REP_OK      0x5a /* request granted */\n#define V4_REP_FAIL    0x5b /* request rejected or failed */\n#define V4_REP_NOIDENT 0x5c /* request failed, could connect to identd */\n#define V4_REP_IDFAIL  0x5d /* request failed, identd denial */\n\n/* Fail for given SOCKSv4 error code. */\nstatic int v4fail(ne_socket *sock, unsigned int code, const char *context)\n{\n    const char *err;\n\n    switch (code) {\n    case V4_REP_FAIL:\n        err = _(\"request rejected or failed\");\n        break;\n    case V4_REP_NOIDENT:\n        err = _(\"could not establish connection to identd\");\n        break;\n    case V4_REP_IDFAIL:\n        err = _(\"rejected due to identd user mismatch\");\n        break;\n    default:\n        ne_sock_set_error(sock, _(\"%s: unrecognized failure (%u)\"),\n                          context, code);\n        return NE_SOCK_ERROR;\n    }\n    \n    ne_sock_set_error(sock, \"%s: %s\", context, err);\n    return NE_SOCK_ERROR;\n}\n\n/* SOCKS v4 or v4A proxy. */\nstatic int v4_proxy(ne_socket *sock, enum ne_sock_sversion vers,\n                    const ne_inet_addr *addr, const char *hostname, \n                    unsigned int port, const char *username)\n{\n    unsigned char msg[1024], raw[16], *p;\n    ssize_t n;\n    int ret;\n\n    p = msg;\n    *p++ = V4_VERSION;\n    *p++ = V4_CMD_STREAM;\n    *p++ = (port >> 8) & 0xff;\n    *p++ = port & 0xff;\n\n    if (vers == NE_SOCK_SOCKSV4A) {\n        /* A bogus address is used to signify use of the hostname,\n         * 0.0.0.X where X != 0. */\n        memcpy(p, \"\\x00\\x00\\x00\\xff\", 4);\n    } \n    else {\n        /* API precondition that addr is IPv4; if it's not this will\n         * just copy out the first four bytes of the v6 address;\n         * garbage in => garbage out. */\n        memcpy(p, ne_iaddr_raw(addr, raw), 4);\n    }\n    p += 4;\n\n    if (username) {\n        unsigned int len = strlen(username) & 0xff;\n        memcpy(p, username, len);\n        p += len;\n    }\n    *p++ = '\\0';\n    \n    if (vers == NE_SOCK_SOCKSV4A) {\n        unsigned int len = strlen(hostname) & 0xff;\n        memcpy(p, hostname, len);\n        p += len;\n        *p++ = '\\0';\n    }    \n\n    ret = ne_sock_fullwrite(sock, (char *)msg, p - msg);\n    if (ret) {\n        return sofail(sock, ret, _(\"Could not send message to proxy\"));\n    }\n\n    n = ne_sock_fullread(sock, (char *)msg, 8);\n    if (n) {\n        return sofail(sock, ret, _(\"Could not read response from proxy\"));\n    }\n    \n    if (msg[1] != V4_REP_OK) {\n        return v4fail(sock, ret, _(\"Could not connect\"));\n    }\n\n    return 0;\n}\n\nint ne_sock_proxy(ne_socket *sock, enum ne_sock_sversion vers,\n                  const ne_inet_addr *addr, const char *hostname, \n                  unsigned int port,\n                  const char *username, const char *password)\n{\n    if (vers == NE_SOCK_SOCKSV5) {\n        return v5_proxy(sock, addr, hostname, port, username, password);\n    }\n    else {\n        return v4_proxy(sock, vers, addr, hostname, port, username);\n    }\n}\n"
  },
  {
    "path": "src/ne_ssl.c",
    "content": "/* \n   Common SSL/TLS handling routines\n   Copyright (C) 2001-2026, Joe Orton <joe@manyfish.co.uk>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n   \n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n*/\n\n#include \"config.h\"\n\n#ifdef HAVE_STRING_H\n#include <string.h>\n#endif\n#ifdef HAVE_STDLIB_H\n#include <stdlib.h>\n#endif\n#ifdef HAVE_ERRNO_H\n#include <errno.h>\n#endif\n\n#include \"ne_alloc.h\"\n#include \"ne_utils.h\"\n#include \"ne_internal.h\"\n#include \"ne_string.h\"\n#include \"ne_privssl.h\"\n\n#ifdef NE_HAVE_SSL\n/* This doesn't actually implement complete RFC 2818 logic; omits\n * \"f*.example.com\" support for simplicity. */\nint ne__ssl_match_hostname(const char *cn, size_t cnlen, const char *hostname)\n{\n    const char *dot;\n\n    if (!hostname) {\n        return 0;\n    }\n\n    NE_DEBUG(NE_DBG_SSL, \"ssl: Match common name '%s' against '%s'\\n\",\n             cn, hostname);\n\n    if (strncmp(cn, \"*.\", 2) == 0 && cnlen > 2\n        && (dot = strchr(hostname, '.')) != NULL) {\n\thostname = dot + 1;\n\tcn += 2;\n        cnlen -= 2;\n    }\n\n    return cnlen == strlen(hostname) && !ne_strcasecmp(cn, hostname);\n}\n\nvoid ne_ssl_context_set_ccprovide(ne_ssl_context *ctx,\n                                  ne_ssl_ccprovide_fn provider, void *userdata)\n{\n    ctx->provider = provider;\n    ctx->provider_ud = userdata;\n}\n\n#endif\n"
  },
  {
    "path": "src/ne_ssl.h",
    "content": "/* \n   SSL/TLS abstraction layer for neon\n   Copyright (C) 2003-2021, Joe Orton <joe@manyfish.co.uk>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n   \n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n\n/* ne_ssl.h defines an interface for loading and accessing the\n * properties of SSL certificates. */\n\n#ifndef NE_SSL_H\n#define NE_SSL_H 1\n\n#include <sys/types.h>\n\n#include \"ne_defs.h\"\n\nNE_BEGIN_DECLS\n\n/* A \"distinguished name\"; a unique name for some entity. */\ntypedef struct ne_ssl_dname_s ne_ssl_dname;\n\n/* Returns a single-line string representation of a distinguished\n * name, intended to be human-readable (e.g. \"Acme Ltd., Norfolk,\n * GB\").  Return value is a UTF-8-encoded malloc-allocated string and\n * must be free'd by the caller. */\nchar *ne_ssl_readable_dname(const ne_ssl_dname *dn);\n\n/* Returns zero if 'dn1' and 'dn2' refer to same name, or non-zero if\n * they are different. */\nint ne_ssl_dname_cmp(const ne_ssl_dname *dn1, const ne_ssl_dname *dn2);\n\n/* An SSL certificate. */\ntypedef struct ne_ssl_certificate_s ne_ssl_certificate;\n\n/* Read a certificate from a file in PEM format; returns NULL if the\n * certificate could not be parsed. */\nne_ssl_certificate *ne_ssl_cert_read(const char *filename);\n\n/* Write a certificate to a file in PEM format; returns non-zero if\n * the certificate could not be written. */\nint ne_ssl_cert_write(const ne_ssl_certificate *cert, const char *filename);\n\n/* Export a certificate to a base64-encoded, NUL-terminated string.\n * The returned string is malloc-allocated and must be free()d by the\n * caller. */\nchar *ne_ssl_cert_export(const ne_ssl_certificate *cert);\n\n/* Import a certificate from a base64-encoded string as returned by\n * ne_ssl_cert_export(). Returns a certificate object or NULL if\n * 'data' was not valid. */\nne_ssl_certificate *ne_ssl_cert_import(const char *data);\n\n/* Returns the identity of the certificate, or NULL if none is given.\n * For a server certificate this will be the hostname of the server to\n * which the cert was issued.  A NUL-terminated UTF-8-encoded string\n * is returned, which is valid for the lifetime of the certificate\n * object. */\nconst char *ne_ssl_cert_identity(const ne_ssl_certificate *cert);\n\n/* Return the certificate of the entity which signed certificate\n * 'cert'.  Returns NULL if 'cert' is self-signed or the issuer\n * certificate is not available; if non-NULL, the pointer is valid for\n * the lifetime of the certificate object. */\nconst ne_ssl_certificate *ne_ssl_cert_signedby(const ne_ssl_certificate *cert);\n\n/* Returns the distinguished name of the certificate issuer. */\nconst ne_ssl_dname *ne_ssl_cert_issuer(const ne_ssl_certificate *cert);\n\n/* Returns the distinguished name of the certificate subject. */\nconst ne_ssl_dname *ne_ssl_cert_subject(const ne_ssl_certificate *cert);\n\n#define NE_SSL_DIGESTLEN (60)\n\n/* Calculate the certificate digest (\"fingerprint\") and format it as a\n * NUL-terminated hex string in 'digest', of the form \"aa:bb:...:ff\".\n * Returns zero on success or non-zero if there was an internal error\n * whilst calculating the digest.  'digest' must be at least \n * NE_SSL_DIGESTLEN bytes in length. */\nint ne_ssl_cert_digest(const ne_ssl_certificate *cert, char *digest);\n\n/* Calculate the certificate digest (\"fingerprint\") and format it as a\n * NUL-terminated hex string using the hash algorithm and formatting\n * flags exactly as if flags was passed to ne_strhash().  Returns NULL\n * on error. */\nchar *ne_ssl_cert_hdigest(const ne_ssl_certificate *cert, unsigned int flags);\n\n/* Copy the validity times for the certificate 'cert' into 'from' and\n * 'until' (either may be NULL).  If the time cannot be represented by\n * a time_t value, then (time_t)-1 will be written. */\nvoid ne_ssl_cert_validity_time(const ne_ssl_certificate *cert,\n                               time_t *from, time_t *until);\n\n#define NE_SSL_VDATELEN (30)\n/* Copy the validity times into buffers 'from' and 'until' as\n * NUL-terminated human-readable strings, using RFC 1123-style date\n * formatting (and not localized, so always using English month/week\n * names).  The buffers must be at least NE_SSL_VDATELEN bytes in\n * length, and either may be NULL. */\nvoid ne_ssl_cert_validity(const ne_ssl_certificate *cert,\n                          char *from, char *until);\n\n/* Returns zero if 'c1' and 'c2' refer to the same certificate, or\n * non-zero otherwise. */\nint ne_ssl_cert_cmp(const ne_ssl_certificate *c1,\n                    const ne_ssl_certificate *c2);\n\n/* Deallocate memory associated with certificate. */\nvoid ne_ssl_cert_free(ne_ssl_certificate *cert);\n\n/* A client certificate (and private key).  A client certificate\n * object has state; the object is either in the \"encrypted\" or\n * \"decrypted\" state.  */\ntypedef struct ne_ssl_client_cert_s ne_ssl_client_cert;\n\n/* Read a client certificate (and private key) in PKCS#12 format from\n * file 'filename'; returns NULL if the file could not be parsed, or\n * otherwise returning a client certificate object.  The returned\n * object may be in either the encrypted or decrypted state. */\nne_ssl_client_cert *ne_ssl_clicert_read(const char *filename);\n\n/* Read a client certificate (and private key) in PKCS#12 format from\n * 'buffer', of length 'buflen', returning NULL if the certificate\n * could not be parsed, or otherwise returning a client certificate\n * object.  The returned object may be in either the encrypted or\n * decrypted state. */\nne_ssl_client_cert *ne_ssl_clicert_import(const unsigned char *buffer, \n                                          size_t buflen);\n\n/* Import a client certificate (and private key) from URI 'uri'. This\n * may be a PKCS#11 URI (RFC 7512); support for other URI schemes is\n * implementation-defined. 'flags' must be zero. Returns a client\n * certificate object on success or NULL on error. On success, the\n * returned object may be in either the encrypted or decrypted\n * state. On error, errno is set to describe the error.\n */\nne_ssl_client_cert *ne_ssl_clicert_fromuri(const char *uri,\n                                           unsigned int flags);\n\n/* Returns non-zero if client cert is in the encrypted state. */\nint ne_ssl_clicert_encrypted(const ne_ssl_client_cert *ccert);\n\n/* Returns the \"friendly name\" given for the client cert, or NULL if\n * none given.  Returns a NUL-terminated, UTF-8-encoded string.  This\n * function may be used on a ccert object in either encrypted or\n * decrypted state. */\nconst char *ne_ssl_clicert_name(const ne_ssl_client_cert *ccert);\n\n/* Decrypt the encrypted client cert using the given password.\n * Returns non-zero on failure, in which case, the ccert object\n * remains in the encrypted state and the function may be called again\n * with a different password.  This function has undefined behaviour\n * for a ccert object which is in the decrypted state. */\nint ne_ssl_clicert_decrypt(ne_ssl_client_cert *ccert, const char *password);\n\n/* Return the actual certificate part of the client certificate (never\n * returns NULL).  This function has undefined behaviour for a ccert\n * object which is in the encrypted state. */\nconst ne_ssl_certificate *ne_ssl_clicert_owner(const ne_ssl_client_cert *ccert);\n\n/* Copy a client certificate object. This function has undefined\n * behaviour for a ccert object which is in the encrypted state. */\nne_ssl_client_cert *ne_ssl_clicert_copy(const ne_ssl_client_cert *ccert);\n\n/* Destroy a client certificate object.  This function may be used on\n * a ccert object in either the encrypted or decrypted state. */\nvoid ne_ssl_clicert_free(ne_ssl_client_cert *ccert);\n\n/* Protocol versions. */\nenum ne_ssl_protocol {\n    NE_SSL_PROTO_UNSPEC = 0,\n    NE_SSL_PROTO_SSL_3,\n    NE_SSL_PROTO_TLS_1_0,\n    NE_SSL_PROTO_TLS_1_1,\n    NE_SSL_PROTO_TLS_1_2,\n    NE_SSL_PROTO_TLS_1_3\n};\n\n/* Return the SSL/TLS protocol name for the protocol version. */\nconst char *ne_ssl_proto_name(enum ne_ssl_protocol proto);\n\n/* NE_SSL_NOTYETVALID: the certificate is not yet valid. */\n#define NE_SSL_NOTYETVALID (0x01)\n\n/* NE_SSL_EXPIRED: the certificate has expired. */\n#define NE_SSL_EXPIRED (0x02)\n\n/* NE_SSL_IDMISMATCH: the hostname for which the certificate was\n * issued does not match the hostname of the server; this could mean\n * that the connection is being intercepted. */\n#define NE_SSL_IDMISMATCH (0x04)\n\n/* NE_SSL_UNTRUSTED: the certificate authority which signed the server\n * certificate is not trusted: there is no indicatation the server is\n * who they claim to be: */\n#define NE_SSL_UNTRUSTED (0x08)\n\n/* NE_SSL_BADCHAIN: the certificate chain contained a certificate\n * other than the server cert which failed verification for a reason\n * other than lack of trust; for example, due to a CA cert being\n * outside its validity period. */\n#define NE_SSL_BADCHAIN (0x10)\n\n/* N.B.: 0x20 is reserved. */\n\n/* NE_SSL_REVOKED: the server certificate has been revoked by the\n * issuing authority. */\n#define NE_SSL_REVOKED (0x40)\n\n/* For purposes of forwards-compatibility, the bitmask of all\n * currently exposed failure bits is given as NE_SSL_FAILMASK.  If the\n * expression (failures & ~NE_SSL_FAILMASK) is non-zero a failure type\n * is present which the application does not recognize but must treat\n * as a verification failure nonetheless. */\n#define NE_SSL_FAILMASK (0x5f)\n\n/* A callback which is used when server certificate verification is\n * needed.  The reasons for verification failure are given in the\n * 'failures' parameter, which is a binary OR of one or more of the\n * above NE_SSL_* values. failures is guaranteed to be non-zero.  The\n * callback must return zero to accept the certificate: a non-zero\n * return value will fail the SSL negotiation. */\ntypedef int (*ne_ssl_verify_fn)(void *userdata, int failures,\n\t\t\t\tconst ne_ssl_certificate *cert);\n\n/* SSL context object.  The interfaces to manipulate an SSL context\n * are only needed when interfacing directly with ne_socket.h. */\ntypedef struct ne_ssl_context_s ne_ssl_context;\n\n/* Context creation modes: */\n#define NE_SSL_CTX_CLIENT (0) /* client context */\n#define NE_SSL_CTX_SERVER (1) /* default server context */\n#define NE_SSL_CTX_SERVERv2 (2) /* unused */\n\n/* Create an SSL context. */\nne_ssl_context *ne_ssl_context_create(int mode);\n\n/* Client mode: trust the given certificate 'cert' in context 'ctx'. */\nvoid ne_ssl_context_trustcert(ne_ssl_context *ctx, const ne_ssl_certificate *cert);\n\n/* Trust the default system CAs. */\nvoid ne_ssl_context_trustdefca(ne_ssl_context *ctx);\n\n/* Server mode: use given cert and key (filenames to PEM certificates). */\nint ne_ssl_context_keypair(ne_ssl_context *ctx,\n                           const char *cert, const char *key);\n\n/* Client mode: use the given client certificate 'cc'.  The client\n * cert MUST be in the decrypted state, otherwise behaviour is\n * undefined.  The client cert object is duplicated internally so can\n * be destroyed by the caller.  */\nvoid ne_ssl_context_set_clicert(ne_ssl_context *ctx, const ne_ssl_client_cert *cc);\n\n/* Callback used to load a client certificate on demand.  If dncount\n * is > 0, the 'dnames' array dnames[0] through dnames[dncount-1]\n * gives the list of CA names which the server indicated were\n * acceptable.  The callback should load an appropriate client\n * certificate and then pass it to 'ne_ssl_set_clicert'. */\ntypedef void (*ne_ssl_ccprovide_fn)(void *userdata,\n                                    const ne_ssl_dname *const *dnames,\n                                    int dncount);\n\n/* Client mode: register a callback to provide a client certificate if\n * requested by the server. */\nvoid ne_ssl_context_set_ccprovide(ne_ssl_context *ctx,\n                                  ne_ssl_ccprovide_fn provider,\n                                  void *userdata);\n\n/* Set the minimum and maximum protocol version which is allowed for\n * the connection. This must be called prior to ne_sock_connect_ssl()\n * or ne_sock_accept_ssl(). Returns 0 on success or NE_SOCK_*. */\nint ne_ssl_context_set_versions(ne_ssl_context *ctx, enum ne_ssl_protocol min,\n                                enum ne_ssl_protocol max);\n\n/* Server mode: set client cert verification options: required is non-zero if \n * a client cert is required, if ca_names is non-NULL it is a filename containing\n * a set of PEM certs from which CA names are sent in the ccert request. */\nint ne_ssl_context_set_verify(ne_ssl_context *ctx, int required,\n                              const char *ca_names, const char *verify_cas);\n\n#define NE_SSL_CTX_SSLv2 (0)\n/* Set a flag for the SSL context. */\nvoid ne_ssl_context_set_flag(ne_ssl_context *ctx, int flag, int value);\n\n/* Return flag value. */\nint ne_ssl_context_get_flag(ne_ssl_context *ctx, int flag);\n\n/* Destroy an SSL context. */\nvoid ne_ssl_context_destroy(ne_ssl_context *ctx);\n\nNE_END_DECLS\n\n#endif\n"
  },
  {
    "path": "src/ne_sspi.c",
    "content": "/* \n   Microsoft SSPI based authentication routines\n   Copyright (C) 2004-2005, Vladimir Berezniker @ http://public.xdi.org/=vmpn\n   Copyright (C) 2007, Yves Martin  <ymartin59@free.fr>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n   \n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n\n#include \"config.h\"\n\n#include \"ne_utils.h\"\n#include \"ne_string.h\"\n#include \"ne_socket.h\"\n#include \"ne_sspi.h\"\n\n#ifdef HAVE_SSPI\n\n#define SEC_SUCCESS(Status) ((Status) >= 0)\n\n#ifndef SECURITY_ENTRYPOINT   /* Missing in MingW 3.7 */\n#define SECURITY_ENTRYPOINT \"InitSecurityInterfaceA\"\n#endif\n\nstruct SSPIContextStruct {\n    CtxtHandle context;\n    char *serverName;\n    CredHandle credentials;\n    int continueNeeded;\n    int authfinished;\n    char *mechanism;\n    int ntlm;\n    ULONG maxTokenSize;\n};\n\ntypedef struct SSPIContextStruct SSPIContext;\n\nstatic ULONG negotiateMaxTokenSize = 0;\nstatic ULONG ntlmMaxTokenSize = 0;\nstatic HINSTANCE hSecDll = NULL;\nstatic PSecurityFunctionTable pSFT = NULL;\nstatic int initialized = 0;\n\n/*\n * Query specified package for it's maximum token size.\n */\nstatic int getMaxTokenSize(char *package, ULONG * maxTokenSize)\n{\n    SECURITY_STATUS status;\n    SecPkgInfo *packageSecurityInfo = NULL;\n\n    status = pSFT->QuerySecurityPackageInfo(package, &packageSecurityInfo);\n    if (status == SEC_E_OK) {\n        *maxTokenSize = packageSecurityInfo->cbMaxToken;\n        if (pSFT->FreeContextBuffer(packageSecurityInfo) != SEC_E_OK) {\n            NE_DEBUG(NE_DBG_HTTPAUTH,\n                     \"sspi: Unable to free security package info.\");\n        }\n    } else {\n        NE_DEBUG(NE_DBG_HTTPAUTH,\n                 \"sspi: QuerySecurityPackageInfo [failed] [%x].\", status);\n        return -1;\n    }\n\n    return 0;\n}\n\n/*\n * Initialize all the SSPI data\n */\nstatic void initDll(HINSTANCE hSecDll)\n{\n    INIT_SECURITY_INTERFACE initSecurityInterface = NULL;\n\n    initSecurityInterface =\n        (INIT_SECURITY_INTERFACE) GetProcAddress(hSecDll,\n                                                 SECURITY_ENTRYPOINT);\n\n    if (initSecurityInterface == NULL) {\n        NE_DEBUG(NE_DBG_HTTPAUTH,\n                 \"sspi: Obtaining security interface [fail].\\n\");\n        initialized = -1;\n        return;\n    } else {\n        NE_DEBUG(NE_DBG_HTTPAUTH,\n                 \"sspi: Obtaining security interface [ok].\\n\");\n    }\n\n    pSFT = (initSecurityInterface) ();\n\n    if (pSFT == NULL) {\n        NE_DEBUG(NE_DBG_HTTPAUTH, \"sspi: Security Function Table [fail].\\n\");\n        initialized = -2;\n        return;\n    } else {\n        NE_DEBUG(NE_DBG_HTTPAUTH, \"sspi: Security Function Table [ok].\\n\");\n    }\n\n    if (getMaxTokenSize(\"Negotiate\", &negotiateMaxTokenSize)) {\n        NE_DEBUG(NE_DBG_HTTPAUTH,\n                 \"sspi: Unable to get negotiate maximum packet size\");\n        initialized = -3;\n    }\n\n    if (getMaxTokenSize(\"NTLM\", &ntlmMaxTokenSize)) {\n        NE_DEBUG(NE_DBG_HTTPAUTH,\n                 \"sspi: Unable to get negotiate maximum packet size\");\n        initialized = -3;\n    }\n}\n\n/*\n * This function needs to be called at least once before using any other.\n */\nint ne_sspi_init(void)\n{\n    if (initialized) {\n        return 0;\n    }\n\n    NE_DEBUG(NE_DBG_SOCKET, \"sspiInit\\n\");\n    NE_DEBUG(NE_DBG_HTTPAUTH, \"sspi: Loading security dll.\\n\");\n    hSecDll = LoadLibrary(\"security.dll\");\n\n    if (hSecDll == NULL) {\n        NE_DEBUG(NE_DBG_HTTPAUTH, \"sspi: Loading of security dll [fail].\\n\");\n    } else {\n        NE_DEBUG(NE_DBG_HTTPAUTH, \"sspi: Loading of security dll [ok].\\n\");\n        initDll(hSecDll);\n        if (initialized == 0) {\n            initialized = 1;\n        }\n    }\n\n    NE_DEBUG(NE_DBG_HTTPAUTH, \"sspi: sspiInit [%d].\\n\", initialized);\n    if (initialized < 0) {\n        return initialized;\n    } else {\n        return 0;\n    }\n}\n\n/*\n * This function can be called to free resources used by SSPI.\n */\nint ne_sspi_deinit(void)\n{\n    NE_DEBUG(NE_DBG_SOCKET, \"sspi: DeInit\\n\");\n    if (initialized <= 0) {\n        return initialized;\n    }\n\n    pSFT = NULL;\n\n    if (hSecDll != NULL) {\n        NE_DEBUG(NE_DBG_HTTPAUTH, \"sspi: Unloading security dll.\\n\");\n        if (FreeLibrary(hSecDll)) {\n            NE_DEBUG(NE_DBG_HTTPAUTH,\n                     \"sspi: Unloading of security dll [ok].\\n\");\n        } else {\n            NE_DEBUG(NE_DBG_HTTPAUTH,\n                     \"sspi: Unloading of security dll [fail].\\n\");\n            return -1;\n        }\n        hSecDll = NULL;\n    }\n\n    initialized = 0;\n    return 0;\n}\n\n/*\n * Simplification wrapper around AcquireCredentialsHandle as most of\n * the parameters do not change.\n */\nstatic int acquireCredentialsHandle(CredHandle * credentials, char *package)\n{\n    SECURITY_STATUS status;\n    TimeStamp timestamp;\n\n    status =\n        pSFT->AcquireCredentialsHandle(NULL, package, SECPKG_CRED_OUTBOUND,\n                                       NULL, NULL, NULL, NULL, credentials,\n                                       &timestamp);\n\n    if (status != SEC_E_OK) {\n        NE_DEBUG(NE_DBG_HTTPAUTH,\n                 \"sspi: AcquireCredentialsHandle [fail] [%x].\\n\", status);\n        return -1;\n    }\n\n    return 0;\n}\n\n/*\n * Wrapper around initializeSecurityContext.  Supplies several\n * default parameters as well as logging in case of errors.\n */\nstatic SECURITY_STATUS\ninitializeSecurityContext(CredHandle * credentials, CtxtHandle * context,\n                          char *spn, ULONG contextReq,\n                          SecBufferDesc * inBuffer, CtxtHandle * newContext,\n                          SecBufferDesc * outBuffer)\n{\n    ULONG contextAttributes;\n    SECURITY_STATUS status;\n\n    status =\n        pSFT->InitializeSecurityContext(credentials, context, spn, contextReq,\n                                        0, SECURITY_NETWORK_DREP, inBuffer, 0,\n                                        newContext, outBuffer,\n                                        &contextAttributes, NULL);\n\n    if (!SEC_SUCCESS(status)) {\n        if (status == SEC_E_INVALID_TOKEN) {\n            NE_DEBUG(NE_DBG_HTTPAUTH,\n                     \"InitializeSecurityContext [fail] SEC_E_INVALID_TOKEN.\\n\");\n        } else if (status == SEC_E_UNSUPPORTED_FUNCTION) {\n            NE_DEBUG(NE_DBG_HTTPAUTH,\n                     \"InitializeSecurityContext [fail] SEC_E_UNSUPPORTED_FUNCTION.\\n\");\n        } else {\n            NE_DEBUG(NE_DBG_HTTPAUTH,\n                     \"InitializeSecurityContext [fail] [%x].\\n\", status);\n        }\n    }\n\n    return status;\n}\n\n/*\n * Validates that the pointer is not NULL and converts it to its real type.\n */\nstatic int getContext(void *context, SSPIContext **sspiContext)\n{\n    if (!context) {\n        return -1;\n    }\n\n    *sspiContext = context;\n    return 0;\n}\n\n/*\n * Verifies that the buffer descriptor point only to one buffer and\n * returns the pointer to it.\n */\nstatic int getSingleBufferDescriptor(SecBufferDesc *secBufferDesc,\n                                     SecBuffer **secBuffer)\n{\n    if (secBufferDesc->cBuffers != 1) {\n        NE_DEBUG(NE_DBG_HTTPAUTH,\n                 \"sspi: fillBufferDescriptor \"\n                 \"[fail] numbers of descriptor buffers. 1 != [%d].\\n\",\n                 secBufferDesc->cBuffers);\n        return -1;\n    }\n\n    *secBuffer = secBufferDesc->pBuffers;\n    return 0;\n}\n\n/*\n * Decodes BASE64 string into SSPI SecBuffer\n */\nstatic int base64ToBuffer(const char *token, SecBufferDesc * secBufferDesc)\n{\n    SecBuffer *buffer;\n    if (getSingleBufferDescriptor(secBufferDesc, &buffer)) {\n        return -1;\n    }\n\n    buffer->BufferType = SECBUFFER_TOKEN;\n    buffer->cbBuffer =\n        ne_unbase64(token, (unsigned char **) &buffer->pvBuffer);\n\n    if (buffer->cbBuffer == 0) {\n        NE_DEBUG(NE_DBG_HTTPAUTH,\n                 \"sspi: Unable to decode BASE64 SSPI token.\\n\");\n        return -1;\n    }\n\n    return 0;\n}\n\n/*\n * Creates a SecBuffer of a specified size.\n */\nstatic int makeBuffer(SecBufferDesc * secBufferDesc, ULONG size)\n{\n    SecBuffer *buffer;\n    if (getSingleBufferDescriptor(secBufferDesc, &buffer)) {\n        return -1;\n    }\n\n    buffer->BufferType = SECBUFFER_TOKEN;\n    buffer->cbBuffer = size;\n    buffer->pvBuffer = ne_calloc(size);\n\n    return 0;\n}\n\n/*\n * Frees data allocated in the buffer.\n */\nstatic int freeBuffer(SecBufferDesc * secBufferDesc)\n{\n    SecBuffer *buffer;\n    if (getSingleBufferDescriptor(secBufferDesc, &buffer)) {\n        return -1;\n    }\n\n    if (buffer->cbBuffer > 0 && buffer->pvBuffer) {\n        ne_free(buffer->pvBuffer);\n        buffer->cbBuffer = 0;\n        buffer->pvBuffer = NULL;\n    }\n\n    return 0;\n}\n\n/*\n * Canonicalize a server host name if possible.\n * The returned pointer must be freed after usage.\n */\nstatic char *canonical_hostname(const char *serverName)\n{\n    const char *hostname;\n    ne_sock_addr *addr;\n    \n    addr = ne_addr_resolve(serverName, NE_ADDR_CANON);\n    if (ne_addr_result(addr) || ne_addr_canonical(addr) == NULL) {\n        /* Lookup failed */\n        char buf[256];\n        NE_DEBUG(NE_DBG_HTTPAUTH,\n                 \"sspi: Could not resolve IP address for `%s': %s\\n\",\n                 serverName, ne_addr_error(addr, buf, sizeof buf));\n        hostname = ne_strdup(serverName);\n    }\n    else {\n        hostname = ne_strdup(ne_addr_canonical(addr));\n    }\n\n    ne_addr_destroy(addr);\n\n    return hostname;\n}\n\n/*\n * Create a context to authenticate to specified server, using either\n * ntlm or negotiate.\n */\nint ne_sspi_create_context(void **context, char *serverName, int ntlm)\n{\n    SSPIContext *sspiContext;\n    char *canonicalName;\n\n    if (initialized <= 0) {\n        return -1;\n    }\n\n    sspiContext = ne_calloc(sizeof(SSPIContext));\n    sspiContext->continueNeeded = 0;\n\n    if (ntlm) {\n        sspiContext->mechanism = \"NTLM\";\n        sspiContext->serverName = ne_strdup(serverName);\n        sspiContext->maxTokenSize = ntlmMaxTokenSize;\n    } else {\n        sspiContext->mechanism = \"Negotiate\";\n        /* Canonicalize to conform to GSSAPI behavior */\n        canonicalName = canonical_hostname(serverName);\n        sspiContext->serverName = ne_concat(\"HTTP/\", canonicalName, NULL);\n        ne_free(canonicalName);\n        NE_DEBUG(NE_DBG_HTTPAUTH, \"sspi: Created context with SPN '%s'\\n\",\n                 sspiContext->serverName);\n        sspiContext->maxTokenSize = negotiateMaxTokenSize;\n    }\n\n    sspiContext->ntlm = ntlm;\n    sspiContext->authfinished = 0;\n    *context = sspiContext;\n    return 0;\n}\n\n/*\n * Resets the context\n */\nstatic void resetContext(SSPIContext * sspiContext)\n{\n    pSFT->DeleteSecurityContext(&(sspiContext->context));\n#if defined(_MSC_VER) && _MSC_VER <= 1200\n    pSFT->FreeCredentialHandle(&(sspiContext->credentials));\n#else\n    pSFT->FreeCredentialsHandle(&(sspiContext->credentials));\n#endif\n    sspiContext->continueNeeded = 0;\n}\n\n/*\n * Initializes supplied SecBufferDesc to point to supplied SecBuffer\n * that is also initialized;\n */\nstatic void\ninitSingleEmptyBuffer(SecBufferDesc * bufferDesc, SecBuffer * buffer)\n{\n    buffer->BufferType = SECBUFFER_EMPTY;\n    buffer->cbBuffer = 0;\n    buffer->pvBuffer = NULL;\n\n    bufferDesc->cBuffers = 1;\n    bufferDesc->ulVersion = SECBUFFER_VERSION;\n    bufferDesc->pBuffers = buffer;\n\n}\n\n/*\n * Destroys the supplied context.\n */\nint ne_sspi_destroy_context(void *context)\n{\n\n    int status;\n    SSPIContext *sspiContext;\n\n    if (initialized <= 0) {\n        return -1;\n    }\n\n    status = getContext(context, &sspiContext);\n    if (status) {\n        return status;\n    }\n\n    resetContext(sspiContext);\n    if (sspiContext->serverName) {\n        ne_free(sspiContext->serverName);\n        sspiContext->serverName = NULL;\n    }\n\n    ne_free(sspiContext);\n    return 0;\n}\nint ne_sspi_clear_context(void *context)\n{\n    int status;\n    SSPIContext *sspiContext;\n\n    if (initialized <= 0) {\n        return -1;\n    }\n\n    status = getContext(context, &sspiContext);\n    if (status) {\n        return status;\n    }\n    sspiContext->authfinished = 0;\n    sspiContext->continueNeeded = 0;\n    return 0;\n}\n/*\n * Processes received authentication tokens as well as supplies the\n * response token.\n */\nint ne_sspi_authenticate(void *context, const char *base64Token, char **responseToken)\n{\n    SecBufferDesc outBufferDesc;\n    SecBuffer outBuffer;\n    int status;\n    SECURITY_STATUS securityStatus;\n    ULONG contextFlags;\n\n    SSPIContext *sspiContext;\n    if (initialized <= 0) {\n        return -1;\n    }\n\n    status = getContext(context, &sspiContext);\n    if (status) {\n        return status;\n    }\n\n    /* TODO: Not sure what flags should be set. joe: this needs to be\n     * driven by the ne_auth interface; the GSSAPI code needs similar\n     * flags. */\n    contextFlags = ISC_REQ_CONFIDENTIALITY | ISC_REQ_MUTUAL_AUTH;\n\n    initSingleEmptyBuffer(&outBufferDesc, &outBuffer);\n    status = makeBuffer(&outBufferDesc, sspiContext->maxTokenSize);\n    if (status) {\n        return status;\n    }\n\n    if (base64Token) {\n        SecBufferDesc inBufferDesc;\n        SecBuffer inBuffer;\n\n        if (!sspiContext->continueNeeded) {\n            freeBuffer(&outBufferDesc);\n            NE_DEBUG(NE_DBG_HTTPAUTH, \"sspi: Got an unexpected token.\\n\");\n            return -1;\n        }\n\n        initSingleEmptyBuffer(&inBufferDesc, &inBuffer);\n\n        status = base64ToBuffer(base64Token, &inBufferDesc);\n        if (status) {\n            freeBuffer(&outBufferDesc);\n            return status;\n        }\n\n        securityStatus =\n            initializeSecurityContext(&sspiContext->credentials,\n                                      &(sspiContext->context),\n                                      sspiContext->serverName, contextFlags,\n                                      &inBufferDesc, &(sspiContext->context),\n                                      &outBufferDesc);\n        if (securityStatus == SEC_E_OK)\n        {\n            sspiContext->authfinished = 1;\n        }\n        freeBuffer(&inBufferDesc);\n    } else {\n        if (sspiContext->continueNeeded) {\n            freeBuffer(&outBufferDesc);\n            NE_DEBUG(NE_DBG_HTTPAUTH, \"sspi: Expected a token from server.\\n\");\n            return -1;\n        }\n        if (sspiContext->authfinished && (sspiContext->credentials.dwLower || sspiContext->credentials.dwUpper)) {\n            if (sspiContext->authfinished)\n            {\n                freeBuffer(&outBufferDesc);\n                sspiContext->authfinished = 0;\n                NE_DEBUG(NE_DBG_HTTPAUTH,\"sspi: failing because starting over from failed try.\\n\");\n                return -1;\n            }\n            sspiContext->authfinished = 0;\n        }\n\n        /* Reset any existing context since we are starting over */\n        resetContext(sspiContext);\n\n        if (acquireCredentialsHandle\n            (&sspiContext->credentials, sspiContext->mechanism) != SEC_E_OK) {\n                freeBuffer(&outBufferDesc);\n                NE_DEBUG(NE_DBG_HTTPAUTH,\n                    \"sspi: acquireCredentialsHandle failed.\\n\");\n                return -1;\n        }\n\n        securityStatus =\n            initializeSecurityContext(&sspiContext->credentials, NULL,\n                                      sspiContext->serverName, contextFlags,\n                                      NULL, &(sspiContext->context),\n                                      &outBufferDesc);\n    }\n\n    if (securityStatus == SEC_I_COMPLETE_AND_CONTINUE\n        || securityStatus == SEC_I_COMPLETE_NEEDED) {\n        SECURITY_STATUS compleStatus =\n            pSFT->CompleteAuthToken(&(sspiContext->context), &outBufferDesc);\n\n        if (compleStatus != SEC_E_OK) {\n            freeBuffer(&outBufferDesc);\n            NE_DEBUG(NE_DBG_HTTPAUTH, \"sspi: CompleteAuthToken failed.\\n\");\n            return -1;\n        }\n    }\n\n    if (securityStatus == SEC_I_COMPLETE_AND_CONTINUE\n        || securityStatus == SEC_I_CONTINUE_NEEDED) {\n        sspiContext->continueNeeded = 1;\n    } else {\n        sspiContext->continueNeeded = 0;\n    }\n\n    if (!(securityStatus == SEC_I_COMPLETE_AND_CONTINUE\n          || securityStatus == SEC_I_COMPLETE_NEEDED\n          || securityStatus == SEC_I_CONTINUE_NEEDED\n          || securityStatus == SEC_E_OK)) {\n        NE_DEBUG(NE_DBG_HTTPAUTH,\n                 \"sspi: initializeSecurityContext [failed] [%x].\\n\",\n                 securityStatus);\n        freeBuffer(&outBufferDesc);\n        return -1;\n    }\n\n    *responseToken = ne_base64(outBufferDesc.pBuffers->pvBuffer,\n                               outBufferDesc.pBuffers->cbBuffer);\n    freeBuffer(&outBufferDesc);\n\n    return 0;\n}\n#endif /* HAVE_SSPI */\n"
  },
  {
    "path": "src/ne_sspi.h",
    "content": "/* \n   Microsoft SSPI based authentication routines\n   Copyright (C) 2004-2005, Vladimir Berezniker @ http://public.xdi.org/=vmpn\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n   \n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n\n#ifndef NE_SSPI_H\n#define NE_SSPI_H\n\n/* Win32 SSPI-based authentication interfaces.  PRIVATE TO NEON -- NOT\n * PART OF THE EXTERNAL API. */\n\n#ifdef HAVE_SSPI\n\n#include <windows.h>\n#define SECURITY_WIN32\n#include <security.h>\n\nint ne_sspi_init(void);\nint ne_sspi_deinit(void);\n\nint ne_sspi_create_context(void **context, char * serverName, int ntlm);\n\nint ne_sspi_destroy_context(void *context);\n\nint ne_sspi_clear_context(void *context);\n\nint ne_sspi_authenticate(void *context, const char *base64Token,\n                         char **responseToken);\n\n#endif /* HAVE_SSPI */\n\n#endif /* NE_SSPI_H */\n"
  },
  {
    "path": "src/ne_string.c",
    "content": "/* \n   String utility functions\n   Copyright (C) 1999-2021, Joe Orton <joe@manyfish.co.uk>\n   strcasecmp/strncasecmp implementations are:\n   Copyright (C) 1991, 1992, 1995, 1996, 1997 Free Software Foundation, Inc.\n   This file is part of the GNU C Library.\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n   \n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n\n#include \"config.h\"\n\n#ifdef HAVE_STDLIB_H\n#include <stdlib.h>\n#endif\n#ifdef HAVE_STRING_H\n#include <string.h>\n#endif\n#ifdef HAVE_UNISTD_H\n#include <unistd.h>\n#endif\n\n#include <stdio.h>\n#include <assert.h>\n#include <errno.h>\n\n#include \"ne_alloc.h\"\n#include \"ne_string.h\"\n#include \"ne_internal.h\"\n\n#ifndef NE_HAVE_SSL\n/* For fallback ne_mknonce() implementation. */\n#ifdef HAVE_GETRANDOM\n#include <sys/random.h>\n#endif\n\n#include \"ne_md5.h\"\n#define NEED_VSTRHASH\n\n#endif\n\nchar *ne_token(char **str, char separator)\n{\n    char *ret = *str, *pnt = strchr(*str, separator);\n\n    if (pnt) {\n\t*pnt = '\\0';\n\t*str = pnt + 1;\n    } else {\n\t/* no separator found: return end of string. */\n\t*str = NULL;\n    }\n    \n    return ret;\n}\n\nchar *ne_qtoken(char **str, char separator, const char *quotes)\n{\n    char *pnt, *ret = NULL;\n\n    for (pnt = *str; *pnt != '\\0'; pnt++) {\n\tconst char *quot = strchr(quotes, *pnt);\n\t\n\tif (quot) {\n\t    char *qclose = strchr(pnt+1, *quot);\n\t    \n\t    if (!qclose) {\n\t\t/* no closing quote: invalid string. */\n\t\treturn NULL;\n\t    }\n\t    \n\t    pnt = qclose;\n\t} else if (*pnt == separator) {\n\t    /* found end of token. */\n\t    *pnt = '\\0';\n\t    ret = *str;\n\t    *str = pnt + 1;\n\t    return ret;\n\t}\n    }\n\n    /* no separator found: return end of string. */\n    ret = *str;\n    *str = NULL;\n    return ret;\n}\n\nchar *ne_shave(char *str, const char *whitespace)\n{\n    char *pnt, *ret = str;\n\n    while (*ret != '\\0' && strchr(whitespace, *ret) != NULL) {\n\tret++;\n    }\n\n    /* pnt points at the NUL terminator. */\n    pnt = &ret[strlen(ret)];\n    \n    while (pnt > ret && strchr(whitespace, *(pnt-1)) != NULL) {\n\tpnt--;\n    }\n\n    *pnt = '\\0';\n    return ret;\n}\n\nvoid ne_buffer_clear(ne_buffer *buf) \n{\n    memset(buf->data, 0, buf->length);\n    buf->used = 1;\n}  \n\n/* Grows for given size, returns 0 on success, -1 on error. */\nvoid ne_buffer_grow(ne_buffer *buf, size_t newsize) \n{\n#define NE_BUFFER_GROWTH 512\n    if (newsize > buf->length) {\n\t/* If it's not big enough already... */\n\tbuf->length = ((newsize / NE_BUFFER_GROWTH) + 1) * NE_BUFFER_GROWTH;\n\t\n\t/* Reallocate bigger buffer */\n\tbuf->data = ne_realloc(buf->data, buf->length);\n    }\n}\n\nstatic size_t count_concat(va_list *ap)\n{\n    size_t total = 0;\n    char *next;\n\n    while ((next = va_arg(*ap, char *)) != NULL)\n\ttotal += strlen(next);\n\n    return total;\n}\n\nstatic void do_concat(char *str, va_list *ap) \n{\n    char *next;\n\n    while ((next = va_arg(*ap, char *)) != NULL) {\n#ifdef HAVE_STPCPY\n        str = stpcpy(str, next);\n#else\n\tsize_t len = strlen(next);\n\tmemcpy(str, next, len);\n\tstr += len;\n#endif\n    }\n}\n\nvoid ne_buffer_concat(ne_buffer *buf, ...)\n{\n    va_list ap;\n    ssize_t total;\n\n    va_start(ap, buf);\n    total = buf->used + count_concat(&ap);\n    va_end(ap);    \n\n    /* Grow the buffer */\n    ne_buffer_grow(buf, total);\n    \n    va_start(ap, buf);    \n    do_concat(buf->data + buf->used - 1, &ap);\n    va_end(ap);    \n\n    buf->used = total;\n    buf->data[total - 1] = '\\0';\n}\n\nchar *ne_concat(const char *str, ...)\n{\n    va_list ap;\n    size_t total, slen = strlen(str);\n    char *ret;\n\n    va_start(ap, str);\n    total = slen + count_concat(&ap);\n    va_end(ap);\n\n    ret = memcpy(ne_malloc(total + 1), str, slen);\n\n    va_start(ap, str);\n    do_concat(ret + slen, &ap);\n    va_end(ap);\n\n    ret[total] = '\\0';\n    return ret;    \n}\n\n/* Append zero-terminated string... returns 0 on success or -1 on\n * realloc failure. */\nvoid ne_buffer_zappend(ne_buffer *buf, const char *str) \n{\n    ne_buffer_append(buf, str, strlen(str));\n}\n\nvoid ne_buffer_append(ne_buffer *buf, const char *data, size_t len) \n{\n    ne_buffer_grow(buf, buf->used + len);\n    memcpy(buf->data + buf->used - 1, data, len);\n    buf->used += len;\n    buf->data[buf->used - 1] = '\\0';\n}\n\nsize_t ne_buffer_snprintf(ne_buffer *buf, size_t max, const char *fmt, ...)\n{\n    va_list ap;\n    size_t ret;\n\n    ne_buffer_grow(buf, buf->used + max);\n\n    va_start(ap, fmt);\n    ret = ne_vsnprintf(buf->data + buf->used - 1, max, fmt, ap);\n    va_end(ap);\n    buf->used += ret;\n\n    return ret;    \n}\n\nne_buffer *ne_buffer_create(void) \n{\n    return ne_buffer_ncreate(512);\n}\n\nne_buffer *ne_buffer_ncreate(size_t s) \n{\n    ne_buffer *buf = ne_malloc(sizeof(*buf));\n    buf->data = ne_malloc(s);\n    buf->data[0] = '\\0';\n    buf->length = s;\n    buf->used = 1;\n    return buf;\n}\n\nvoid ne_buffer_destroy(ne_buffer *buf) \n{\n    ne_free(buf->data);\n    ne_free(buf);\n}\n\nchar *ne_buffer_finish(ne_buffer *buf)\n{\n    char *ret = buf->data;\n    ne_free(buf);\n    return ret;\n}\n\nvoid ne_buffer_altered(ne_buffer *buf)\n{\n    buf->used = strlen(buf->data) + 1;\n}\n\n/* ascii_quote[n] gives the number of bytes needed by\n * ne_buffer_qappend() to append character 'n'. */\n/* Generated with 'mktable quote', do not alter here -- */\nstatic const unsigned char table_quote[256] = {\n/* x00 */ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,\n/* x10 */ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,\n/* x20 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n/* x30 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n/* x40 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n/* x50 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n/* x60 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n/* x70 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4,\n/* x80 */ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,\n/* x90 */ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,\n/* xA0 */ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,\n/* xB0 */ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,\n/* xC0 */ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,\n/* xD0 */ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,\n/* xE0 */ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,\n/* xF0 */ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4\n}; /* -- Generated code from 'mktable quote' ends. */\n\nstatic const char hex_chars[16] = \"0123456789abcdef\";\n\n/* Return the expected number of bytes needed to append the string\n * beginning at byte 's', where 'send' points to the last byte after\n * 's'. */ \nstatic size_t qappend_count(const unsigned char *s, const unsigned char *send)\n{\n    const unsigned char *p;\n    size_t ret;\n    \n    for (p = s, ret = 0; p < send; p++) {\n        ret += table_quote[*p];\n    }\n\n    return ret;\n}       \n\n/* Append the string 's', up to but not including 'send', to string\n * 'dest', quoting along the way.  Returns pointer to NUL. */\nstatic char *quoted_append(char *dest, const unsigned char *s, \n                           const unsigned char *send)\n{\n    const unsigned char *p;\n    char *q = dest;\n\n    for (p = s; p < send; p++) {\n        if (table_quote[*p] == 1) {\n            *q++ = *p;\n        }\n        else {\n            *q++ = '\\\\';\n            *q++ = 'x';\n            *q++ = hex_chars[(*p >> 4) & 0x0f];\n            *q++ = hex_chars[*p & 0x0f];\n        }\n    }\n\n    /* NUL terminate after the last character */\n    *q = '\\0';\n    \n    return q;\n}\n\nvoid ne_buffer_qappend(ne_buffer *buf, const unsigned char *data, size_t len)\n{\n    const unsigned char *dend = data + len;\n    char *q, *qs;\n\n    ne_buffer_grow(buf, buf->used + qappend_count(data, dend));\n\n    /* buf->used >= 1, so this is safe. */\n    qs = buf->data + buf->used - 1;\n\n    q = quoted_append(qs, data, dend);\n    \n    /* used already accounts for a NUL, so increment by number of\n     * characters appended, *before* the NUL. */\n    buf->used += q - qs;\n}\n\nchar *ne_strnqdup(const unsigned char *data, size_t len)\n{\n    const unsigned char *dend = data + len;\n    char *dest = ne_malloc(qappend_count(data, dend) + 1);\n\n    quoted_append(dest, data, dend);\n\n    return dest;\n}\n\nstatic const char b64_alphabet[] =  \n    \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\"\n    \"abcdefghijklmnopqrstuvwxyz\"\n    \"0123456789+/=\";\n    \nchar *ne_base64(const unsigned char *text, size_t inlen)\n{\n    /* The tricky thing about this is doing the padding at the end,\n     * doing the bit manipulation requires a bit of concentration only */\n    char *buffer, *point;\n    size_t outlen;\n    \n    /* Use 'buffer' to store the output. Work out how big it should be...\n     * This must be a multiple of 4 bytes */\n\n    outlen = (inlen*4)/3;\n    if ((inlen % 3) > 0) /* got to pad */\n\toutlen += 4 - (inlen % 3);\n    \n    buffer = ne_malloc(outlen + 1); /* +1 for the \\0 */\n    \n    /* now do the main stage of conversion, 3 bytes at a time,\n     * leave the trailing bytes (if there are any) for later */\n\n    for (point=buffer; inlen>=3; inlen-=3, text+=3) {\n\t*(point++) = b64_alphabet[ (*text)>>2 ]; \n\t*(point++) = b64_alphabet[ ((*text)<<4 & 0x30) | (*(text+1))>>4 ]; \n\t*(point++) = b64_alphabet[ ((*(text+1))<<2 & 0x3c) | (*(text+2))>>6 ];\n\t*(point++) = b64_alphabet[ (*(text+2)) & 0x3f ];\n    }\n\n    /* Now deal with the trailing bytes */\n    if (inlen > 0) {\n\t/* We always have one trailing byte */\n\t*(point++) = b64_alphabet[ (*text)>>2 ];\n\t*(point++) = b64_alphabet[ (((*text)<<4 & 0x30) |\n\t\t\t\t     (inlen==2?(*(text+1))>>4:0)) ]; \n\t*(point++) = (inlen==1?'=':b64_alphabet[ (*(text+1))<<2 & 0x3c ]);\n\t*(point++) = '=';\n    }\n\n    /* Null-terminate */\n    *point = '\\0';\n\n    return buffer;\n}\n\n/* Generated with 'mktable validb64', do not alter here -- */\nstatic const unsigned char table_validb64[256] = {\n/* x00 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n/* x10 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n/* x20 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1,\n/* x30 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0,\n/* x40 */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n/* x50 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,\n/* x60 */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n/* x70 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,\n/* x80 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n/* x90 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n/* xA0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n/* xB0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n/* xC0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n/* xD0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n/* xE0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n/* xF0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n}; /* -- Generated code from 'mktable validb64' ends. */\n\n/* Generated with 'mktable decodeb64', do not alter here -- */\nstatic const unsigned char table_decodeb64[256] = {\n/* x00 */ 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,\n/* x08 */ 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,\n/* x10 */ 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,\n/* x18 */ 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,\n/* x20 */ 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,\n/* x28 */ 0x3f, 0x3f, 0x3f, 0x3e, 0x3f, 0x3f, 0x3f, 0x3f,\n/* x30 */ 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,\n/* x38 */ 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43,\n/* x40 */ 0x44, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,\n/* x48 */ 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,\n/* x50 */ 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,\n/* x58 */ 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e,\n/* x60 */ 0x1f, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,\n/* x68 */ 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,\n/* x70 */ 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,\n/* x78 */ 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,\n/* x80 */ 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40,\n/* x88 */ 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,\n/* x90 */ 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50,\n/* x98 */ 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,\n/* xA0 */ 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60,\n/* xA8 */ 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,\n/* xB0 */ 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,\n/* xB8 */ 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,\n/* xC0 */ 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80,\n/* xC8 */ 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88,\n/* xD0 */ 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90,\n/* xD8 */ 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,\n/* xE0 */ 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0,\n/* xE8 */ 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8,\n/* xF0 */ 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0,\n/* xF8 */ 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8\n}; /* -- Generated code from 'mktable decodeb64' ends. */\n\n#define DECODE_B64(ch) table_decodeb64[ch]\n#define VALID_B64(ch) table_validb64[ch]\n\nsize_t ne_unbase64(const char *data, unsigned char **out)\n{\n    size_t inlen = strlen(data);\n    unsigned char *outp;\n    const unsigned char *in;\n\n    if (inlen == 0 || (inlen % 4) != 0) return 0;\n    \n    outp = *out = ne_malloc(inlen * 3 / 4);\n\n    for (in = (const unsigned char *)data; *in; in += 4) {\n        unsigned int tmp;\n        if (!VALID_B64(in[0]) || !VALID_B64(in[1]) || !VALID_B64(in[2]) ||\n            !VALID_B64(in[3]) || in[0] == '=' || in[1] == '=' ||\n            (in[2] == '=' && in[3] != '=')) {\n            ne_free(*out);\n            return 0;\n        }\n        tmp = (DECODE_B64(in[0]) & 0x3f) << 18 |\n            (DECODE_B64(in[1]) & 0x3f) << 12;\n        *outp++ = (tmp >> 16) & 0xff;\n        if (in[2] != '=') {\n            tmp |= (DECODE_B64(in[2]) & 0x3f) << 6;\n            *outp++ = (tmp >> 8) & 0xff;\n            if (in[3] != '=') {\n                tmp |= DECODE_B64(in[3]) & 0x3f;\n                *outp++ = tmp & 0xff;\n            }\n        }\n    }\n\n    return outp - *out;\n}\n\n/* Character map array; table_strclean[n] = isprint(n) ? n : 0x20.  Used\n * by ne_strclean as a locale-independent isprint(). */\n/* Generated with 'mktable strclean', do not alter here -- */\nstatic const unsigned char table_strclean[256] = {\n/* x00 */ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,\n/* x08 */ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,\n/* x10 */ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,\n/* x18 */ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,\n/* x20 */ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,\n/* x28 */ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,\n/* x30 */ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,\n/* x38 */ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,\n/* x40 */ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,\n/* x48 */ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,\n/* x50 */ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,\n/* x58 */ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,\n/* x60 */ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,\n/* x68 */ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,\n/* x70 */ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,\n/* x78 */ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x20,\n/* x80 */ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,\n/* x88 */ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,\n/* x90 */ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,\n/* x98 */ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,\n/* xA0 */ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,\n/* xA8 */ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,\n/* xB0 */ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,\n/* xB8 */ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,\n/* xC0 */ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,\n/* xC8 */ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,\n/* xD0 */ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,\n/* xD8 */ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,\n/* xE0 */ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,\n/* xE8 */ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,\n/* xF0 */ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,\n/* xF8 */ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20\n}; /* -- Generated code from 'mktable strclean' ends. */\n\nchar *ne_strclean(char *str)\n{\n    unsigned char *pnt;\n\n    for (pnt = (unsigned char *)str; *pnt; pnt++)\n        *pnt = (char)table_strclean[*pnt];\n\n    return str;\n}\n\nchar *ne_strerror(int errnum, char *buf, size_t buflen)\n{\n#ifdef HAVE_STRERROR_R\n#ifdef STRERROR_R_CHAR_P\n    /* glibc-style strerror_r which may-or-may-not use provided buffer. */\n    char *ret = strerror_r(errnum, buf, buflen);\n    if (ret != buf)\n\tne_strnzcpy(buf, ret, buflen);\n#else /* POSIX-style strerror_r: */\n    char tmp[256];\n\n    if (strerror_r(errnum, tmp, sizeof tmp) == 0)\n        ne_strnzcpy(buf, tmp, buflen);\n    else\n        ne_snprintf(buf, buflen, \"Unknown error %d\", errnum);\n#endif\n#else /* no strerror_r: */\n    ne_strnzcpy(buf, strerror(errnum), buflen);\n#endif\n    return buf;\n}\n\n\n/* Wrapper for ne_snprintf. */\nsize_t ne_snprintf(char *str, size_t size, const char *fmt, ...)\n{\n    va_list ap;\n    va_start(ap, fmt);\n#ifdef HAVE_TRIO\n    trio_vsnprintf(str, size, fmt, ap);\n#else\n    vsnprintf(str, size, fmt, ap);\n#endif\n    va_end(ap);\n    str[size-1] = '\\0';\n    return strlen(str);\n}\n\n/* Wrapper for ne_vsnprintf. */\nsize_t ne_vsnprintf(char *str, size_t size, const char *fmt, va_list ap)\n{\n#ifdef HAVE_TRIO\n    trio_vsnprintf(str, size, fmt, ap);\n#else\n    vsnprintf(str, size, fmt, ap);\n#endif\n    str[size-1] = '\\0';\n    return strlen(str);\n}\n\n/* Generated with 'mktable tolower', do not alter here -- */\nstatic const unsigned char table_tolower[256] = {\n/* x00 */ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,\n/* x08 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,\n/* x10 */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,\n/* x18 */ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,\n/* x20 */ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,\n/* x28 */ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,\n/* x30 */ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,\n/* x38 */ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,\n/* x40 */ 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,\n/* x48 */ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,\n/* x50 */ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,\n/* x58 */ 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,\n/* x60 */ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,\n/* x68 */ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,\n/* x70 */ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,\n/* x78 */ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,\n/* x80 */ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,\n/* x88 */ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,\n/* x90 */ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,\n/* x98 */ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,\n/* xA0 */ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,\n/* xA8 */ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,\n/* xB0 */ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,\n/* xB8 */ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,\n/* xC0 */ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,\n/* xC8 */ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,\n/* xD0 */ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,\n/* xD8 */ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,\n/* xE0 */ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,\n/* xE8 */ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,\n/* xF0 */ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,\n/* xF8 */ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff\n}; /* -- Generated code from 'mktable tolower' ends. */\n\n#define TOLOWER(ch) table_tolower[ch]\n\nconst unsigned char *ne_tolower_array(void)\n{\n    return table_tolower;\n}\n\nchar *ne_strlower(char *str)\n{\n    unsigned char *p = (unsigned char *)str;\n\n    do {\n        *p = TOLOWER(*p);\n    } while (*p++);\n\n    return str;\n}\n\n/* Generated with 'mktable toupper', do not alter here -- */\nstatic const unsigned char table_toupper[256] = {\n/* x00 */ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,\n/* x08 */ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,\n/* x10 */ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,\n/* x18 */ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,\n/* x20 */ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,\n/* x28 */ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,\n/* x30 */ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,\n/* x38 */ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,\n/* x40 */ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,\n/* x48 */ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,\n/* x50 */ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,\n/* x58 */ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,\n/* x60 */ 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,\n/* x68 */ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,\n/* x70 */ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,\n/* x78 */ 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,\n/* x80 */ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,\n/* x88 */ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,\n/* x90 */ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,\n/* x98 */ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,\n/* xA0 */ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,\n/* xA8 */ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,\n/* xB0 */ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,\n/* xB8 */ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,\n/* xC0 */ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,\n/* xC8 */ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,\n/* xD0 */ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,\n/* xD8 */ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,\n/* xE0 */ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,\n/* xE8 */ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,\n/* xF0 */ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,\n/* xF8 */ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff\n}; /* -- Generated code from 'mktable toupper' ends. */\n\n#define TOUPPER(ch) table_toupper[ch]\n\nchar *ne_strupper(char *str)\n{\n    unsigned char *p = (unsigned char *)str;\n\n    do {\n        *p = TOUPPER(*p);\n    } while (*p++);\n\n    return str;\n}\n\nint ne_strcasecmp(const char *s1, const char *s2)\n{\n    const unsigned char *p1 = (const unsigned char *) s1;\n    const unsigned char *p2 = (const unsigned char *) s2;\n    unsigned char c1, c2;\n\n    if (p1 == p2)\n        return 0;\n    \n    do {\n        c1 = TOLOWER(*p1++);\n        c2 = TOLOWER(*p2++);\n        if (c1 == '\\0')\n            break;\n    } while (c1 == c2);\n    \n    return c1 - c2;\n}\n\nint ne_strncasecmp(const char *s1, const char *s2, size_t n)\n{\n    const unsigned char *p1 = (const unsigned char *) s1;\n    const unsigned char *p2 = (const unsigned char *) s2;\n    unsigned char c1, c2;\n    \n    if (p1 == p2 || n == 0)\n        return 0;\n    \n    do {\n        c1 = TOLOWER(*p1++);\n        c2 = TOLOWER(*p2++);\n        if (c1 == '\\0' || c1 != c2)\n            return c1 - c2;\n    } while (--n > 0);\n    \n    return c1 - c2;\n}\n\nchar *ne_strhash(unsigned int flags, ...)\n{\n    va_list ap;\n    char *rv;\n    \n    va_start(ap, flags);\n    rv = ne_vstrhash(flags, ap);\n    va_end(ap);\n\n    return rv;\n}\n\n#ifdef NEED_VSTRHASH\nchar *ne_vstrhash(unsigned int flags, va_list ap)\n{\n    const char *arg;\n    struct ne_md5_ctx *ctx;\n    unsigned int resbuf[4];\n\n    if ((flags & NE_HASH_ALGMASK) != NE_HASH_MD5) return NULL;\n\n    ctx = ne_md5_create_ctx();\n    if (!ctx) return NULL;\n\n    while ((arg = va_arg(ap, const char *)) != NULL)\n        ne_md5_process_bytes(arg, strlen(arg), ctx);\n\n    ne_md5_finish_ctx(ctx, resbuf);\n    ne_md5_destroy_ctx(ctx);\n\n    return ne__strhash2hex((void *)&resbuf, sizeof resbuf, flags);\n}\n#endif\n\n#define HEX2ASC(a) (hex_chars[((unsigned char)(a)) & 0xf])\n\nchar *ne__strhash2hex(const unsigned char *digest, size_t len,\n                      unsigned int flags)\n{\n    unsigned char sep = '\\0';\n    size_t step = 2;\n    char *rv, *p;\n    size_t n;\n\n    assert(len > 0);\n\n    if ((flags & NE_HASH_COLON)) {\n        step = 3;\n        sep = ':';\n    }\n    else if ((flags & NE_HASH_SPACE)) {\n        step = 3;\n        sep = ' ';\n    }\n\n    p = rv = ne_malloc(len * step + 1);\n\n    for (n = 0; n < len; n++) {\n        *p++ = HEX2ASC(digest[n] >> 4);\n        *p++ = HEX2ASC(digest[n] & 0x0f);\n        if (sep) *p++ = sep;\n    }\n\n    if (sep) p--;\n\n    *p = '\\0';\n    return rv;\n}\n\n#ifndef NE_HAVE_SSL\nint ne_mknonce(unsigned char *nonce, size_t len, unsigned int flags)\n{\n#ifdef HAVE_GETRANDOM\n    ssize_t ret = getrandom(nonce, len, 0);\n\n    if (ret < 0)\n        return errno;\n    else if ((size_t)ret != len)\n        return EINVAL;\n\n    return 0;\n#else\n    return ENOTSUP;\n#endif\n}\n#endif /* !NE_HAVE_SSL */\n\n/* Generated with 'mktable extparam', do not alter here -- */\nstatic const unsigned char table_extparam[256] = {\n/* x00 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,\n/* x10 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,\n/* x20 */ 3, 1, 3, 1, 1, 3, 1, 3, 3, 3, 3, 1, 3, 1, 1, 3,\n/* x30 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3,\n/* x40 */ 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n/* x50 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 1, 1,\n/* x60 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n/* x70 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 3,\n/* x80 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,\n/* x90 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,\n/* xA0 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,\n/* xB0 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,\n/* xC0 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,\n/* xD0 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,\n/* xE0 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,\n/* xF0 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3\n}; /* -- Generated code from 'mktable extparam' ends. */\n\nchar *ne_strparam(const char *charset, const char *lang,\n                  const unsigned char *value)\n{\n    const unsigned char *p;\n    size_t count = 0;\n    char *rv, *rp;\n\n    /* Determine length required for the value. */\n    for (p = value; *p; p++)\n        count += table_extparam[*p];\n\n    /* If length == input length, no encoding is required, return\n     * NULL. */\n    if (count == strlen((const char *)value)) return NULL;\n\n    /* +3 accounts for '' and trailing NUL */\n    rv = ne_malloc(strlen(charset) + (lang ? strlen(lang) : 0) + count + 3);\n    memcpy(rv, charset, strlen(charset));\n    rp = rv + strlen(charset);\n    *rp++ = '\\'';\n    if (lang) {\n        memcpy(rp, lang, strlen(lang));\n        rp += strlen(lang);\n    }\n    *rp++ = '\\'';\n\n    for (p = value; *p; p++) {\n        if (table_extparam[*p] == 1)  {\n            *rp++ = *p;\n        }\n        else {\n            *rp++ = '%';\n            *rp++ = HEX2ASC(*p >> 4);\n            *rp++ = HEX2ASC(*p & 0x0f);\n        }\n    }\n\n    *rp = '\\0';\n\n    return rv;\n}\n\nunsigned long ne_strhextoul(const char *str, const char **end)\n{\n    unsigned long ret;\n    char *p;\n\n    if ((str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))\n        || !((str[0] >= '0' && str[0] <= '9')\n             || (str[0] >= 'A' && str[0] <= 'Z')\n             || (str[0] >= 'a' && str[0] <= 'z'))) {\n        errno = EINVAL;\n        p = (char *)str;\n        ret = ULONG_MAX;\n    }\n    else {\n        errno = 0;\n        ret = strtoul(str, &p, 16);\n    }\n    if (end) *end = (const char *)p;\n\n    return ret;\n}\n"
  },
  {
    "path": "src/ne_string.h",
    "content": "/* \n   String utility functions\n   Copyright (C) 1999-2021, Joe Orton <joe@manyfish.co.uk>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n   \n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n\n#ifndef NE_STRING_H\n#define NE_STRING_H\n\n#include \"ne_defs.h\"\n#include \"ne_alloc.h\"\n\n#include <stdarg.h>\n\nNE_BEGIN_DECLS\n\n/* ne_token and ne_qtoken return the next token in *str before either\n * the next separator character 'sep' or the NUL terminator.\n * ne_qtoken skips over any parts quoted using a pair of any one of\n * the characters given in 'quotes'.  After returning, *str will point\n * to the next character after the separator, or NULL if no separator\n * character was found.\n * \n * ne_qtoken will return NULL if unterminated quotes are found. */\nchar *ne_token(char **str, char sep);\nchar *ne_qtoken(char **str, char sep, const char *quotes);\n\n/* Return portion of 'str' with any characters in 'whitespace' shaved\n * off the beginning and end.  Modifies str in-place. */\nchar *ne_shave(char *str, const char *whitespace);\n\n/* Cleanse 'str' of non-printable (e.g. control) characters.  'str' is\n * modified in-place, and returned. */\nchar *ne_strclean(char *str)\n    ne_attribute((nonnull));\n\n/* Encode 'len' bytes of 'text' to base64.  Returns malloc-allocated\n * NUL-terminated buffer which the caller must free(). */\nchar *ne_base64(const unsigned char *text, size_t len)\n    ne_attribute_malloc;\n\n/* Decode NUL-terminated base64-encoded string 'data', placing\n * malloc-allocated raw decoder output in '*out'.  Returns length, or\n * zero on decode error (in which case the content of *out is\n * undefined). */\nsize_t ne_unbase64(const char *data, unsigned char **out);\n\n/* Dynamically-allocated string buffer.  A string buffer which grows\n * dynamically . (Strings are zero-terminated still).  A\n * string buffer ne_buffer which grows dynamically with the string. */\ntypedef struct {\n    char *data; /* contents: NUL-terminated string */\n    size_t used; /* strlen(data) + 1 */\n    size_t length; /* number of bytes allocated */\n} ne_buffer;\n\n/* Create a new string buffer object. */\nne_buffer *ne_buffer_create(void);\n\n/* Create a new string buffer object with at least 'size' bytes of\n * allocated space. */\nne_buffer *ne_buffer_ncreate(size_t size);\n\n/* Returns size of data in buffer, equiv to strlen(ne_buffer_data(buf)) */\n#define ne_buffer_size(buf) ((buf)->used - 1)\n\n/* Concatenate all given strings onto the end of the buffer.  The\n * strings must all be NUL-terminated, and MUST be followed by a NULL\n * argument marking the end of the list.  */\nvoid ne_buffer_concat(ne_buffer *buf, ...)\n    ne_attribute_sentinel;\n\n/* Append a NUL-terminated string 'str' to buf. */\nvoid ne_buffer_zappend(ne_buffer *buf, const char *str);\n\n/* Append 'len' bytes of 'data' to buf, where 'data' does not contain\n * a NUL terminator.  (A NUL terminator is appended to buf) */\nvoid ne_buffer_append(ne_buffer *buf, const char *data, size_t len);\n\n/* Append 'len' bytes of 'data' to buf.  All non-ASCII bytes, and\n * ASCII control characters, are escaped.  (Note that this includes\n * the NUL byte). */\nvoid ne_buffer_qappend(ne_buffer *buf, const unsigned char *data, size_t len);\n\n/* Print a string to the end of the buffer using printf-style format\n * string 'format' and subsqeuent arguments.  At most 'max' characters\n * are appended; the number of characters appended (excluding the NUL\n * terminator) is returned.  Behaviour is undefined if 'max' is passed\n * as zero. */\nsize_t ne_buffer_snprintf(ne_buffer *buf, size_t max, \n                          const char *format, ...)\n    ne_attribute((format(printf, 3, 4)));\n\n/* Append a literal, NUL-terminated constant string 'str' to buffer\n * 'buf'. */\n#define ne_buffer_czappend(buf, str) \\\nne_buffer_append((buf), (str), sizeof((str)) - 1)\n\n/* Clear the string buffer 'buf', making it equivalent to the empty\n * string. */\nvoid ne_buffer_clear(ne_buffer *buf);\n\n/* Grow the allocated size of string buffer 'buf' to at least 'size'\n * bytes. */\nvoid ne_buffer_grow(ne_buffer *buf, size_t size);\n\n/* Re-establish the 'used' invariant if the string buffer data field is\n * altered directly. */\nvoid ne_buffer_altered(ne_buffer *buf);\n\n/* Destroy the string buffer object 'buf' without deallocating the\n * data string.  The data string must subsequently be freed using\n * ne_free(). */\nchar *ne_buffer_finish(ne_buffer *buf);\n\n/* Destroy a string buffer object. */\nvoid ne_buffer_destroy(ne_buffer *buf);\n\n/* Thread-safe strerror() wrapper; place system error for errno value\n * 'errnum' in 'buffer', which is of length 'buflen'.  Returns\n * 'buffer'. */\nchar *ne_strerror(int errnum, char *buffer, size_t buflen);\n\n/* ne_strnzcpy copies at most 'n'-1 bytes of 'src' to 'dest', and\n * ensures that 'dest' is subsequently NUL-terminated. */\n#define ne_strnzcpy(dest, src, n) do { size_t ne__nm1 = (n) - 1;      \\\nstrncpy(dest, src, ne__nm1); dest[ne__nm1] = '\\0'; } while (0)\n\n/* Return a malloc-allocated copy of 'data', of length 'len', with all\n * non-ASCII bytes, and ASCII control characters escaped.  (Note that\n * the escaping includes the NUL byte). */\nchar *ne_strnqdup(const unsigned char *data, size_t len)\n    ne_attribute_malloc;\n\n/* Return malloc-allocated concatenation of all NUL-terminated string\n * arguments, up to a terminating NULL pointer. */\nchar *ne_concat(const char *str, ...)\n    ne_attribute_sentinel;\n\n/* Hash algorithms: */\n#define NE_HASH_MD5        (0x0001) /* MD5 */\n#define NE_HASH_SHA256     (0x0002) /* SHA-256 (SHA-2) */\n#define NE_HASH_SHA512     (0x0003) /* SHA-512 (SHA-2) */\n#define NE_HASH_SHA512_256 (0x0004) /* SHA-512/256 (SHA-2) */\n#define NE_HASH_SHA1       (0x0005) /* SHA-1 */\n\n/* Optional hash output formatting options: */\n#define NE_HASH_COLON      (0x1000) /* Colon-separated pairs */\n#define NE_HASH_SPACE      (0x2000) /* Space-separated pairs */\n\n/* Calculate hash over concatenation of NUL-terminated const char *\n * string arguments, up to a terminating NULL pointer, and return as a\n * malloc-allocated ASCII hex string.  'flags' comprises exactly one\n * of the algorithms indicated by the NE_HASH_* values above, which\n * may optionally be combined with the formatting options.  Returns\n * NULL if the hash type is not supported or an internal error\n * occurs. */\nchar *ne_strhash(unsigned int flags, ...)\n    ne_attribute_sentinel ne_attribute_malloc;\n/* Equivalent of ne_strhash(), taking va_list argument; the behaviour\n * is otherwise identical. */\nchar *ne_vstrhash(unsigned int flags, va_list ap)\n    ne_attribute_malloc;\n\n/* Generates a nonce of length 'len', which must be no greater than\n * 256. 'flags' must be zero. Returns zero on success, or an errno\n * value on error. */\nint ne_mknonce(unsigned char *nonce, size_t len, unsigned int flags);\n\n/* Wrapper for snprintf: always NUL-terminates returned buffer, and\n * returns strlen(str). */\nsize_t ne_snprintf(char *str, size_t size, const char *fmt, ...)\n    ne_attribute((format(printf, 3, 4)));\n\n/* Wrapper for vsnprintf. */\nsize_t ne_vsnprintf(char *str, size_t size, const char *fmt, va_list ap)\n    ne_attribute((format(printf, 3, 0)));\n\n/* Implementations of strcasecmp and strncasecmp which behave as\n * defined by the ANSI C strcasecmp() and strncasecmp() when in the\n * POSIX locale; i.e. ignoring the process locale. */\n\n/* Compares 's1' and 's2', ignoring differences in case. */\nint ne_strcasecmp(const char *s1, const char *s2);\n/* Compares up to 'n' characters of 's1' and 's2', ignoring\n * differences in case. */\nint ne_strncasecmp(const char *s1, const char *s2, size_t n);\n\n/* Return lowercase 'c' as in POSIX locale; note difference from ANSI\n * C semantics as both the argument and return value are unsigned\n * char. */\n#define ne_tolower(c) (ne_tolower_array()[(unsigned char)c])\n\nconst unsigned char *ne_tolower_array(void) ne_attribute((const));\n\n/* Modifies every character in 'str' to lower-case in-place, returning\n * 'str'. */\nchar *ne_strlower(char *str);\n\n/* Modifies every character in 'str' to upper-case in-place, returning\n * 'str'. */\nchar *ne_strupper(char *str);\n\n/* Convert an ASCII hexadecimal character in the ranges '0'..'9'\n * 'a'..'f' 'A'..'F' to its numeric equivalent. */\n#define NE_ASC2HEX(x) (((x) <= '9') ? ((x) - '0') : \\\n                       (ne_tolower((x)) + 10 - 'a'))\n\n/* Convert an integer in the range 0..15 to the equivalent (lowercase)\n * ASCII hexadecimal equivalent character, in the range '0..9,'a..f' */\n#define NE_HEX2ASC(x) ((char) ((x) > 9 ? ((x) - 10 + 'a') : ((x) + '0')))\n\n/* Encodes a extended parameter value for HTTP headers, as defined in\n * RFC 5987.  Returns a malloc-allocated string if the parameter\n * 'value' needs to be encoded as an extended parameter, or NULL if it\n * can be used as a regular parameter.  The charset must be either\n * \"UTF-8\" or \"ISO-8859-1\", but the language value can be NULL. */\nchar *ne_strparam(const char *charset, const char *lang,\n                  const unsigned char *value)\n    ne_attribute((nonnull (1, 3))) ne_attribute_malloc;\n\n/* Parse a hex string like strtoul(,,16), but:\n * a) any whitespace, 0x or -/+ prefixes result in EINVAL\n * b) errno is always set (to zero or an error)\n * c) end pointer is const char *\n */\nunsigned long ne_strhextoul(const char *str, const char **endptr);\n\nNE_END_DECLS\n\n#endif /* NE_STRING_H */\n"
  },
  {
    "path": "src/ne_stubssl.c",
    "content": "/* \n   Stubs for SSL support when no SSL library has been configured\n   Copyright (C) 2002-2021, Joe Orton <joe@manyfish.co.uk>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n   \n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n\n#include \"config.h\"\n\n#include <stdlib.h> /* for NULL */\n\n#include \"ne_ssl.h\"\n#include \"ne_session.h\"\n#include \"ne_socket.h\"\n\nchar *ne_ssl_readable_dname(const ne_ssl_dname *dn)\n{\n    return NULL;\n}\n\nne_ssl_certificate *ne_ssl_cert_read(const char *filename)\n{\n    return NULL;\n}\n\nint ne_ssl_cert_cmp(const ne_ssl_certificate *c1, const ne_ssl_certificate *c2)\n{\n    return 1;\n}\n\nconst ne_ssl_certificate *ne_ssl_cert_signedby(const ne_ssl_certificate *cert)\n{ \n    return NULL;\n}\n\nconst ne_ssl_dname *ne_ssl_cert_issuer(const ne_ssl_certificate *cert)\n{\n    return NULL;\n}\n\nconst ne_ssl_dname *ne_ssl_cert_subject(const ne_ssl_certificate *cert)\n{\n    return NULL;\n}\n\nvoid ne_ssl_cert_free(ne_ssl_certificate *cert) {}\n\nne_ssl_client_cert *ne_ssl_clicert_read(const char *filename)\n{\n    return NULL;\n}\n\nconst ne_ssl_certificate *ne_ssl_clicert_owner(const ne_ssl_client_cert *ccert)\n{\n    return NULL;\n}\n\nne_ssl_client_cert *ne_ssl_clicert_import(const unsigned char *buffer, \n                                          size_t buflen)\n{\n    return NULL;\n}\n\nint ne_ssl_clicert_encrypted(const ne_ssl_client_cert *ccert)\n{\n    return -1;\n}\n\nint ne_ssl_clicert_decrypt(ne_ssl_client_cert *ccert, const char *password)\n{\n    return -1;\n}\n\nvoid ne_ssl_clicert_free(ne_ssl_client_cert *ccert) {}\n\nne_ssl_context *ne_ssl_context_create(int mode)\n{\n    return NULL;\n}\n\nvoid ne_ssl_context_trustcert(ne_ssl_context *ctx, const ne_ssl_certificate *cert) {}\nint ne_ssl_context_keypair(ne_ssl_context *ctx,\n                           const char *cert, const char *key)\n{\n    return -1;\n}\n\nint ne_ssl_context_set_versions(ne_ssl_context *ctx, enum ne_ssl_protocol min,\n                                enum ne_ssl_protocol max)\n{\n    return NE_SOCK_ERROR;\n}\nint ne_ssl_check_certificate(ne_ssl_context *ctx, ne_socket *sock,\n                             const char *hostname,\n                             const ne_inet_addr *address,\n                             const ne_ssl_certificate *cert,\n                             unsigned int flags, int *failures)\n{\n    return -1;\n}\n\nint ne_ssl_context_set_verify(ne_ssl_context *ctx, \n                              int required,\n                              const char *ca_names,\n                              const char *verify_cas)\n{\n    return -1;\n}\n\nvoid ne_ssl_context_set_clicert(ne_ssl_context *ctx, const ne_ssl_client_cert *cc)\n{}\n\nvoid ne_ssl_context_set_flag(ne_ssl_context *ctx, int flag, int value) {}\nint ne_ssl_context_get_flag(ne_ssl_context *ctx, int flag) { return -1; }\nvoid ne_ssl_context_trustdefca(ne_ssl_context *ctx) {}\nvoid ne_ssl_context_destroy(ne_ssl_context *ctx) {}\nvoid ne_ssl_context_set_ccprovide(ne_ssl_context *ctx,\n                                  ne_ssl_ccprovide_fn provider,\n                                  void *userdata) {}\n\nint ne_ssl_cert_digest(const ne_ssl_certificate *cert, char *digest)\n{\n    return -1;\n}\n\nchar *ne_ssl_cert_hdigest(const ne_ssl_certificate *cert, unsigned int flags)\n{\n    return NULL;\n}\n\nvoid ne_ssl_cert_validity_time(const ne_ssl_certificate *cert,\n                               time_t *from, time_t *until) {}\n\nconst char *ne_ssl_cert_identity(const ne_ssl_certificate *cert)\n{\n    return NULL;\n}\n\n\nconst char *ne_ssl_clicert_name(const ne_ssl_client_cert *ccert)\n{\n    return NULL;\n}\n\nint ne_ssl_dname_cmp(const ne_ssl_dname *dn1, const ne_ssl_dname *dn2)\n{\n    return -1;\n}\n\nint ne_ssl_cert_write(const ne_ssl_certificate *cert, const char *filename)\n{\n    return -1;\n}\n\nchar *ne_ssl_cert_export(const ne_ssl_certificate *cert)\n{\n    return NULL;\n}\n\nne_ssl_certificate *ne_ssl_cert_import(const char *data)\n{\n    return NULL;\n}\n\nne_ssl_client_cert *ne_ssl_clicert_copy(const ne_ssl_client_cert *cc)\n\n{\n    return NULL;\n}\n\nne_ssl_client_cert *ne_ssl_clicert_fromuri(const char *uri,\n                                           unsigned int flags)\n{\n    return NULL;\n}\n\nint ne_sock_accept_ssl(ne_socket *sock, ne_ssl_context *ctx) {\n    return NE_SOCK_ERROR;\n}\n\nint ne_sock_connect_ssl(ne_socket *sock, ne_ssl_context *ctx, void *userdata)\n{\n    return NE_SOCK_ERROR;\n}\n\nint ne_sock_handshake(ne_socket *sock, ne_ssl_context *ctx,\n                      const char *hostname, unsigned int flags)\n\n{\n    return NE_SOCK_ERROR;\n}\n"
  },
  {
    "path": "src/ne_uri.c",
    "content": "/* \n   URI manipulation routines.\n   Copyright (C) 1999-2025, Joe Orton <joe@manyfish.co.uk>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n   \n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n\n#include \"config.h\"\n\n#ifdef HAVE_STRING_H\n#include <string.h>\n#endif\n#ifdef HAVE_STRINGS_H\n#include <strings.h>\n#endif\n#ifdef HAVE_UNISTD_H\n#include <unistd.h>\n#endif\n#ifdef HAVE_STDLIB_H\n#include <stdlib.h>\n#endif\n\n#include <stdio.h>\n\n#include <ctype.h>\n\n#include \"ne_string.h\" /* for ne_buffer */\n#include \"ne_alloc.h\"\n#include \"ne_uri.h\"\n\n/* Character classes defined from URI ABNF from RFC 3986. */\n\n#define PS (0x0001) /* \"+\" */\n#define PC (0x0002) /* \"%\" */\n#define DS (0x0004) /* \"-\" */\n#define DT (0x0008) /* \".\" */\n#define US (0x0010) /* \"_\" */\n#define TD (0x0020) /* \"~\" */\n#define FS (0x0040) /* \"/\" */\n#define CL (0x0080) /* \":\" */\n#define AT (0x0100) /* \"@\" */\n#define QU (0x0200) /* \"?\" */\n\n#define DG (0x0400) /* DIGIT */\n#define AL (0x0800) /* ALPHA */\n\n#define GD (0x1000) /* gen-delims    = \"#\" / \"[\" / \"]\" \n                     * ... except \":\", \"/\", \"@\", and \"?\" */\n\n#define SD (0x2000) /* sub-delims    = \"!\" / \"$\" / \"&\" / \"'\" / \"(\" / \")\"\n                     *               / \"*\" / \"+\" / \",\" / \";\" / \"=\" \n                     * ... except \"+\" which is PS */\n\n#define OT (0x4000) /* others */\n/* UNUSED  (0x8000) .. only remaining bit. */\n\n/* ALL defined characters classes, note that 0x8000 is an unused class\n * bit so is not (currently) included. */\n#define URI_ALL (0x7FFF)\n\n#define URI_ALPHA (AL)\n#define URI_DIGIT (DG)\n#define URI_NONURI (OT)\n\n/* unreserved = ALPHA / DIGIT / \"-\" / \".\" / \"_\" / \"~\" */\n#define URI_UNRESERVED (AL | DG | DS | DT | US | TD)\n/* scheme = ALPHA *( ALPHA / DIGIT / \"+\" / \"-\" / \".\" ) */\n#define URI_SCHEME (AL | DG | PS | DS | DT)\n/* real sub-delims definition, including \"+\" */\n#define URI_SUBDELIM (PS | SD)\n/* real gen-delims definition, including \":\", \"/\", \"@\" and \"?\" */\n#define URI_GENDELIM (GD | CL | FS | AT | QU)\n/* userinfo = *( unreserved / pct-encoded / sub-delims / \":\" ) */\n#define URI_USERINFO (URI_UNRESERVED | PC | URI_SUBDELIM | CL)\n/* pchar = unreserved / pct-encoded / sub-delims / \":\" / \"@\" */\n#define URI_PCHAR (URI_UNRESERVED | PC | URI_SUBDELIM | CL | AT)\n/* invented: segchar = pchar / \"/\" */\n#define URI_SEGCHAR (URI_PCHAR | FS)\n/* query = *( pchar / \"/\" / \"?\" ) */\n#define URI_QUERY (URI_PCHAR | FS | QU)\n/* fragment == query */\n#define URI_FRAGMENT URI_QUERY\n\n/* Used previously for the ne_path_escape() rule, or NE_PATH_NONRES\n * flag for ne_path_escapef(): */\n#define URI_OLD_ESCAPE ((URI_GENDELIM & ~(FS)) | URI_SUBDELIM | OT | PC)\n\n/* Characters which should be pct-encoded are the INVERSE of the\n * SEGCHAR class. Used now by ne_path_escape() and the NE_PATH_NONPC\n * rule. */\n#define URI_ESCAPE ((URI_ALL & ~(URI_SEGCHAR)) | PC)\n\n/* Maximum allowed port number. */\n#define MAX_PORT (65535)\n\nstatic const unsigned short uri_chars[256] = {\n/* 0xXX    x0      x2      x4      x6      x8      xA      xC      xE     */\n/*   0x */ OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT,\n/*   1x */ OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT,\n/*   2x */ OT, SD, OT, GD, SD, PC, SD, SD, SD, SD, SD, PS, SD, DS, DT, FS,\n/*   3x */ DG, DG, DG, DG, DG, DG, DG, DG, DG, DG, CL, SD, OT, SD, OT, QU,\n/*   4x */ AT, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL,\n/*   5x */ AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, GD, OT, GD, OT, US,\n/*   6x */ OT, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL,\n/*   7x */ AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, AL, OT, OT, OT, TD, OT,\n/*   8x */ OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, \n/*   9x */ OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, \n/*   Ax */ OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, \n/*   Bx */ OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, \n/*   Cx */ OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, \n/*   Dx */ OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, \n/*   Ex */ OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, \n/*   Fx */ OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT, OT\n};\n\n#define uri_lookup(ch) (uri_chars[(unsigned char)ch])\n\nchar *ne_path_parent(const char *uri) \n{\n    size_t len = strlen(uri);\n    const char *pnt = uri + len - 1;\n    /* skip trailing slash (parent of \"/foo/\" is \"/\") */\n    if (pnt >= uri && *pnt == '/')\n\tpnt--;\n    /* find previous slash */\n    while (pnt > uri && *pnt != '/')\n\tpnt--;\n    if (pnt < uri || (pnt == uri && *pnt != '/'))\n\treturn NULL;\n    return ne_strndup(uri, pnt - uri + 1);\n}\n\nint ne_path_has_trailing_slash(const char *uri) \n{\n    size_t len = strlen(uri);\n    return ((len > 0) &&\n\t    (uri[len-1] == '/'));\n}\n\nunsigned int ne_uri_defaultport(const char *scheme)\n{\n    /* Scheme matching is case-insensitive per RFC 3986§3.1 */\n    if (ne_strcasecmp(scheme, \"http\") == 0)\n\treturn 80;\n    else if (ne_strcasecmp(scheme, \"https\") == 0)\n\treturn 443;\n    else\n\treturn 0;\n}\n\nint ne_uri_parse(const char *uri, ne_uri *parsed)\n{\n    const char *p, *s;\n\n    memset(parsed, 0, sizeof *parsed);\n\n    p = s = uri;\n\n    /* => s = p = URI-reference */\n\n    if (uri_lookup(*p) & URI_ALPHA) {\n        while (uri_lookup(*p) & URI_SCHEME)\n            p++;\n        \n        if (*p == ':') {\n            parsed->scheme = ne_strndup(uri, p - s);\n            s = p + 1;\n        }\n    }\n\n    /* => s = heir-part, or s = relative-part */\n\n    if (s[0] == '/' && s[1] == '/') {\n        const char *pa;\n\n        /* => s = \"//\" authority path-abempty (from expansion of\n         * either heir-part of relative-part)  */\n        \n        /* authority = [ userinfo \"@\" ] host [ \":\" port ] */\n\n        s = pa = s + 2; /* => s = authority */\n\n        while (*pa != '/' && *pa != '?' && *pa != '#' && *pa != '\\0')\n            pa++;\n        /* => pa = path-abempty */\n        \n        p = s;\n        while (p < pa && uri_lookup(*p) & URI_USERINFO)\n            p++;\n\n        if (*p == '@') {\n            parsed->userinfo = ne_strndup(s, p - s);\n            s = p + 1;\n        }\n        /* => s = host */\n\n        if (s[0] == '[') {\n            p = s + 1;\n\n            /* This allows any characters in IP-literal which is too\n             * broad, however e.g. zone identifiers per RFC 6874 are\n             * allowed through. */\n            while (*p != ']' && p < pa)\n                p++;\n\n            if (p == pa || (p + 1 != pa && p[1] != ':')) {\n                /* Ill-formed IP-literal. */\n                return -1;\n            }\n\n            p++; /* => p = [ ':' port ] */\n        } else {\n            /* Find any colon before reaching path-abempty. */\n            p = s;\n            while (*p != ':' && p < pa)\n                p++;\n        }\n        /* => p = [ \":\" port ] */\n\n        parsed->host = ne_strndup(s, p - s);\n\n        /* Iff p and pa (=> path-abempty) differ, the optional port\n         * section is present and parsed here: */\n        if (p != pa) {\n            unsigned int port = 0;\n\n            if (*p++ != ':') return -1;\n\n            /* => p = port */\n\n            /* port = *DIGIT\n             *\n             * Note: port can be the empty string, in which case now:\n             * p == pa and port is parsed as 0, as desired. */\n            while (p < pa && port <= MAX_PORT && (uri_lookup(*p) & URI_DIGIT) != 0)\n                port = 10*port + *p++-'0';\n\n            /* If p did not reach pa there was some non-digit present\n             * or the integer was too large, so fail. */\n            if (p != pa || port > MAX_PORT) return -1;\n\n            parsed->port = port;\n        }\n        \n        s = pa; /* Next, parse path-abempty */\n    }\n\n    /* => s = path-abempty / path-absolute / path-rootless\n     *      / path-empty / path-noscheme */\n\n    p = s;\n\n    while (uri_lookup(*p) & URI_SEGCHAR)\n        p++;\n\n    /* => p = [ \"?\" query ] [ \"#\" fragment ] */\n\n    if (p != s || parsed->host == NULL)\n        parsed->path = ne_strndup(s, p - s);\n    else\n        parsed->path = ne_strdup(\"/\");  /* FIXME: scheme-specific. */\n\n    if (*p != '\\0') {\n        s = p++;\n\n        while (uri_lookup(*p) & URI_QUERY)\n            p++;\n\n        /* => p = [ \"#\" fragment ] */\n        /* => s = [ \"?\" query ] [ \"#\" fragment ] */\n\n        if (*s == '?') {\n            parsed->query = ne_strndup(s + 1, p - s - 1);\n            \n            if (*p != '\\0') {\n                s = p++;\n\n                while (uri_lookup(*p) & URI_FRAGMENT)\n                    p++;\n            }\n        }\n\n        /* => p now points to the next character after the\n         * URI-reference; which should be the NUL byte. */\n\n        if (*s == '#') {\n            parsed->fragment = ne_strndup(s + 1, p - s - 1);\n        }\n        else if (*p || *s != '?') {\n            return -1;\n        }\n    }\n    \n    return 0;\n}\n\n/* This function directly implements the \"Merge Paths\" algorithm\n * described in RFC 3986 section 5.2.3. */\nstatic char *merge_paths(const ne_uri *base, const char *path)\n{\n    const char *p;\n\n    if (base->host && base->path[0] == '\\0') {\n        return ne_concat(\"/\", path, NULL);\n    }\n    \n    p = strrchr(base->path, '/');\n    if (p == NULL) {\n        return ne_strdup(path);\n    } else {\n        size_t len = p - base->path + 1;\n        char *ret = ne_malloc(strlen(path) + len + 1);\n\n        memcpy(ret, base->path, len);\n        memcpy(ret + len, path, strlen(path) + 1);\n        return ret;\n    }\n}\n\n/* This function directly implements the \"Remove Dot Segments\"\n * algorithm described in RFC 3986 section 5.2.4. */\nstatic char *remove_dot_segments(const char *path)\n{\n    char *in, *inc, *out;\n\n    inc = in = ne_strdup(path);\n    out = ne_malloc(strlen(path) + 1);\n    out[0] = '\\0';\n\n    while (in[0]) {\n        /* case 2.A: */\n        if (strncmp(in, \"./\", 2) == 0) {\n            in += 2;\n        } \n        else if (strncmp(in, \"../\", 3) == 0) {\n            in += 3;\n        }\n\n        /* case 2.B: */\n        else if (strncmp(in, \"/./\", 3) == 0) {\n            in += 2;\n        }\n        else if (strcmp(in, \"/.\") == 0) {\n            in[1] = '\\0';\n        }\n\n        /* case 2.C: */\n        else if (strncmp(in, \"/../\", 4) == 0 || strcmp(in, \"/..\") == 0) {\n            char *p;\n\n            /* Make the next character in the input buffer a \"/\": */\n            if (in[3] == '\\0') {\n                /* terminating \"/..\" case */\n                in += 2;\n                in[0] = '/';\n            } else {\n                /* \"/../\" prefix case */\n                in += 3;\n            }\n\n            /* Trim the last component from the output buffer, or\n             * empty it. */\n            p = strrchr(out, '/');\n            if (p) {\n                *p = '\\0';\n            } else {\n                out[0] = '\\0';\n            }\n        }\n\n        /* case 2.D: */\n        else if (strcmp(in, \".\") == 0 || strcmp(in, \"..\") == 0) {\n            in[0] = '\\0';\n        }\n\n        /* case 2.E */\n        else {\n            char *p;\n\n            /* Search for the *second* \"/\" if the leading character is\n             * already \"/\": */\n            p = strchr(in + (in[0] == '/'), '/');\n            /* Otherwise, copy the whole string */\n            if (p == NULL) p = strchr(in, '\\0');\n\n            strncat(out, in, p - in);\n            in = p;\n        }\n    }\n\n    ne_free(inc);\n\n    return out;\n}\n\n/* Copy authority components from 'src' to 'dest' if defined. */\nstatic void copy_authority(ne_uri *dest, const ne_uri *src)\n{\n    if (src->host) dest->host = ne_strdup(src->host);\n    dest->port = src->port;\n    if (src->userinfo) dest->userinfo = ne_strdup(src->userinfo);\n}\n\n/* This function directly implements the \"Transform References\"\n * algorithm described in RFC 3986 section 5.2.2. */\nne_uri *ne_uri_resolve(const ne_uri *base, const ne_uri *relative,\n                       ne_uri *target)\n{\n    memset(target, 0, sizeof *target);\n\n    if (relative->scheme) {\n        target->scheme = ne_strdup(relative->scheme);\n        copy_authority(target, relative);\n        target->path = remove_dot_segments(relative->path);\n        if (relative->query) target->query = ne_strdup(relative->query);\n    } else {\n        if (relative->host) {\n            copy_authority(target, relative);\n            target->path = remove_dot_segments(relative->path);\n            if (relative->query) target->query = ne_strdup(relative->query);\n        } else {\n            if (relative->path[0] == '\\0') {\n                target->path = ne_strdup(base->path);\n                if (relative->query) {\n                    target->query = ne_strdup(relative->query);\n                } else if (base->query) {\n                    target->query = ne_strdup(base->query);\n                }\n            } else {\n                if (relative->path[0] == '/') {\n                    target->path = remove_dot_segments(relative->path);\n                } else {\n                    char *merged = merge_paths(base, relative->path);\n                    target->path = remove_dot_segments(merged);\n                    ne_free(merged);\n                }\n                if (relative->query) target->query = ne_strdup(relative->query);\n            }\n            copy_authority(target, base);\n        }\n        if (base->scheme) target->scheme = ne_strdup(base->scheme);\n    }\n    \n    if (relative->fragment) target->fragment = ne_strdup(relative->fragment);\n\n    return target;\n}\n\nne_uri *ne_uri_copy(ne_uri *dest, const ne_uri *src)\n{\n    memset(dest, 0, sizeof *dest);\n\n    if (src->scheme) dest->scheme = ne_strdup(src->scheme);\n    copy_authority(dest, src);\n    if (src->path) dest->path = ne_strdup(src->path);\n    if (src->query) dest->query = ne_strdup(src->query);\n    if (src->fragment) dest->fragment = ne_strdup(src->fragment);\n\n    return dest;\n}\n\nvoid ne_uri_free(ne_uri *u)\n{\n    if (u->host) ne_free(u->host);\n    if (u->path) ne_free(u->path);\n    if (u->scheme) ne_free(u->scheme);\n    if (u->userinfo) ne_free(u->userinfo);\n    if (u->fragment) ne_free(u->fragment);\n    if (u->query) ne_free(u->query);\n    memset(u, 0, sizeof *u);\n}\n\nchar *ne_path_unescape(const char *uri) \n{\n    const char *pnt;\n    char *ret, *retpos, buf[5] = { \"0x00\" };\n    retpos = ret = ne_malloc(strlen(uri) + 1);\n    for (pnt = uri; *pnt != '\\0'; pnt++) {\n\tif (*pnt == '%') {\n\t    if (!isxdigit((unsigned char) pnt[1]) || \n\t\t!isxdigit((unsigned char) pnt[2])) {\n\t\t/* Invalid URI */\n                ne_free(ret);\n\t\treturn NULL;\n\t    }\n\t    buf[2] = *++pnt; buf[3] = *++pnt; /* bit faster than memcpy */\n\t    *retpos++ = (char)strtol(buf, NULL, 16);\n\t} else {\n\t    *retpos++ = *pnt;\n\t}\n    }\n    *retpos = '\\0';\n    return ret;\n}\n\n/* CH must be an unsigned char; evaluates to 1 if CH should be\n * percent-encoded (note !!x == x ? 1 : 0). */\n#define path_escape_ch(ch, mask) (!!(uri_lookup(ch) & (mask)))\n\nchar *ne_path_escape(const char *path)\n{\n    return ne_path_escapef(path, NE_PATH_NONPC);\n}\n\nchar *ne_path_escapef(const char *path, unsigned int flags)\n{\n    const unsigned char *pnt;\n    char *ret, *p;\n    size_t count = 0;\n    unsigned short mask = 0;\n\n    if (flags & NE_PATH_NONRES) mask |= URI_OLD_ESCAPE;\n    if (flags & NE_PATH_NONURI) mask |= URI_NONURI;\n    if (flags & NE_PATH_NONPC) mask |= URI_ESCAPE;\n\n    for (pnt = (const unsigned char *)path; *pnt != '\\0'; pnt++) {\n        count += path_escape_ch(*pnt, mask);\n    }\n\n    if (count == 0) {\n\treturn ne_strdup(path);\n    }\n\n    p = ret = ne_malloc(strlen(path) + 2 * count + 1);\n    for (pnt = (const unsigned char *)path; *pnt != '\\0'; pnt++) {\n\tif (path_escape_ch(*pnt, mask)) {\n\t    /* Escape it - %<hex><hex> */\n\t    ne_snprintf(p, 4, \"%%%02x\", (unsigned char) *pnt);\n\t    p += 3;\n\t} else {\n\t    *p++ = *pnt;\n\t}\n    }\n    *p = '\\0';\n    return ret;\n}\n\n#undef path_escape_ch\n\n#define CMPWITH(field, func)                    \\\n    do {                                        \\\n        if (u1->field) {                        \\\n            if (!u2->field) return -1;          \\\n            n = func(u1->field, u2->field);     \\\n            if (n) return n;                    \\\n        } else if (u2->field) {                 \\\n            return 1;                           \\\n        }                                       \\\n    } while (0)\n\n#define CMP(field) CMPWITH(field, strcmp)\n#define CASECMP(field) CMPWITH(field, ne_strcasecmp)\n\n/* As specified by RFC 2616, section 3.2.3. */\nint ne_uri_cmp(const ne_uri *u1, const ne_uri *u2)\n{\n    int n;\n    \n    CMP(path);\n    CASECMP(host);\n    CASECMP(scheme);\n    CMP(query);\n    CMP(fragment);\n    CMP(userinfo);\n\n    return u2->port - u1->port;\n}\n\n#undef CMP\n#undef CASECMP\n#undef CMPWITH\n\n/* TODO: implement properly */\nint ne_path_compare(const char *a, const char *b) \n{\n    int ret = ne_strcasecmp(a, b);\n    if (ret) {\n\t/* This logic says: \"If the lengths of the two URIs differ by\n\t * exactly one, and the LONGER of the two URIs has a trailing\n\t * slash and the SHORTER one DOESN'T, then...\" */\n\tint traila = ne_path_has_trailing_slash(a),\n\t    trailb = ne_path_has_trailing_slash(b),\n\t    lena = strlen(a), lenb = strlen(b);\n\tif (traila != trailb && abs(lena - lenb) == 1 &&\n\t    ((traila && lena > lenb) || (trailb && lenb > lena))) {\n\t    /* Compare them, ignoring the trailing slash on the longer\n\t     * URI */\n\t    if (strncasecmp(a, b, lena < lenb ? lena : lenb) == 0)\n\t\tret = 0;\n\t}\n    }\n    return ret;\n}\n\nchar *ne_uri_unparse(const ne_uri *uri)\n{\n    ne_buffer *buf = ne_buffer_create();\n\n    if (uri->scheme) {\n        ne_buffer_concat(buf, uri->scheme, \":\", NULL);\n    }\n\n    if (uri->host) {\n        ne_buffer_czappend(buf, \"//\");\n        if (uri->userinfo) {\n            ne_buffer_concat(buf, uri->userinfo, \"@\", NULL);\n        }\n        ne_buffer_zappend(buf, uri->host);\n        \n        if (uri->port > 0\n            && (!uri->scheme \n                || ne_uri_defaultport(uri->scheme) != uri->port)) {\n            ne_buffer_snprintf(buf, 20, \":%d\", uri->port);\n        }\n    }\n\n    ne_buffer_zappend(buf, uri->path);\n\n    if (uri->query) {\n        ne_buffer_concat(buf, \"?\", uri->query, NULL);\n    }\n    \n    if (uri->fragment) {\n        ne_buffer_concat(buf, \"#\", uri->fragment, NULL);\n    }\n\n    return ne_buffer_finish(buf);\n}\n\n/* Give it a path segment, it returns non-zero if child is \n * a child of parent. */\nint ne_path_childof(const char *parent, const char *child) \n{\n    char *root = ne_strdup(child);\n    int ret;\n    if (strlen(parent) >= strlen(child)) {\n\tret = 0;\n    } else {\n\t/* root is the first of child, equal to length of parent */\n\troot[strlen(parent)] = '\\0';\n\tret = (ne_path_compare(parent, root) == 0);\n    }\n    ne_free(root);\n    return ret;\n}\n"
  },
  {
    "path": "src/ne_uri.h",
    "content": "/* \n   URI manipulation routines.\n   Copyright (C) 1999-2025, Joe Orton <joe@manyfish.co.uk>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n   \n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n\n#ifndef NE_URI_H\n#define NE_URI_H\n\n#include \"ne_defs.h\"\n\nNE_BEGIN_DECLS\n\n/* Return a copy of a path string with anything not allowed in the URI\n * \"pchar\" rule, or the forward-slash character, percent-escaped. This\n * is equivalent to calling ne_path_escapef() with the NE_PATH_NONPC\n * flag. Returns a malloc-allocated string and never NULL. */\nchar *ne_path_escape(const char *path)\n    ne_attribute((nonnull));\n\n/* Flags for ne_path_escapef():\n *\n * NE_PATH_NONRES - matching behaviour of ne_path_escape() prior to\n * neon 0.35.0, percent-encodes anything other than \"unreserved\" and\n * the forward-slash character.\n * NE_PATH_NONURI - pct-encodes characters outside of those allowed\n * in URIs.\n * NE_PATH_NONPC - pct-encodes characters which are not allowed in\n * either the URI \"pchar\" rule or a forward slash; i.e. characters\n * which are not allowed in path definitions. */\n#define NE_PATH_NONRES (0x0001)\n#define NE_PATH_NONURI (0x0002)\n#define NE_PATH_NONPC  (0x0004)\n\n/* Return a copy of a path string with escaping applied per rules\n * determined by any combination of NE_PATH_* flags given.  Returns a\n * malloc-allocated string and never NULL. */\nchar *ne_path_escapef(const char *path, unsigned int flags)\n    ne_attribute((nonnull));\n\n/* Return a decoded copy of a percent-encoded path string. Returns\n * malloc-allocated path on success, or NULL if the string contained\n * any syntactically invalid percent-encoding sequences. */\nchar *ne_path_unescape(const char *epath)\n    ne_attribute((nonnull));\n\n/* Returns malloc-allocated parent of path, or NULL if path has no\n * parent (such as \"/\"). */\nchar *ne_path_parent(const char *path)\n    ne_attribute((nonnull));\n\n/* Returns strcmp-like value giving comparison between p1 and p2,\n * ignoring trailing-slashes. */\nint ne_path_compare(const char *p1, const char *p2)\n    ne_attribute((nonnull));\n\n/* Returns non-zero if child is a child of parent. */\nint ne_path_childof(const char *parent, const char *child)\n    ne_attribute((nonnull));\n\n/* Returns non-zero if path has a trailing slash character. */\nint ne_path_has_trailing_slash(const char *path)\n    ne_attribute((nonnull));\n\n/* Return the default port for the given scheme, or 0 if none is\n * known. */\nunsigned int ne_uri_defaultport(const char *scheme)\n    ne_attribute((nonnull));\n\ntypedef struct {\n    char *scheme;\n    char *host, *userinfo;\n    unsigned int port;\n    char *path, *query, *fragment;\n} ne_uri;\n\n/* Parse a URI-reference 'uri' and place parsed components in *parsed.\n * Returns zero on success, non-zero on parse error.  On successful or\n * error return, all the 'char *' fields of *parsed are either set to\n * NULL, or point to malloc-allocated NUL-terminated strings;\n * ne_uri_free can be used to free any set fields.  On success,\n * parsed->path is guaranteed to be non-NULL. */\nint ne_uri_parse(const char *uri, ne_uri *parsed)\n    ne_attribute((nonnull));\n\n/* Turns a URI structure back into a string.  The returned string is\n * malloc-allocated, and must be freed by the caller. */\nchar *ne_uri_unparse(const ne_uri *uri)\n    ne_attribute((nonnull));\n\n/* Resolve a relative URI 'relative', with respect to base URI 'base',\n * placing the resultant URI in '*result'.  At least both base->path\n * and relative->path must be non-NULL.  On return, all the 'char *'\n * fields of *result are either set to NULL or point to\n * malloc-allocated NUL-terminated strings.  result->path is\n * guaranteed to be non-NULL.  ne_uri_free can be used to free the\n * result structure after use.  Returns 'result'. */\nne_uri *ne_uri_resolve(const ne_uri *base, const ne_uri *relative,\n                       ne_uri *result)\n    ne_attribute((nonnull));\n\n/* Compares URIs u1 and u2, returns non-zero if they are found to be\n * non-equal.  The sign of the return value is <0 if 'u1' is less than\n * 'u2', or >0 if 'u2' is greater than 'u1'. */\nint ne_uri_cmp(const ne_uri *u1, const ne_uri *u2)\n    ne_attribute((nonnull));\n\n/* Copy components of URI 'src' to destination 'dest'.  Returns\n * 'dest'. */\nne_uri *ne_uri_copy(ne_uri *dest, const ne_uri *src)\n    ne_attribute((nonnull));\n\n/* Frees any non-NULL fields of parsed URI structure *parsed.  All\n * fields are then zero-initialized. */\nvoid ne_uri_free(ne_uri *parsed)\n    ne_attribute((nonnull));\n\nNE_END_DECLS\n\n#endif /* NE_URI_H */\n\n"
  },
  {
    "path": "src/ne_utils.c",
    "content": "/* \n   HTTP utility functions\n   Copyright (C) 1999-2024, Joe Orton <joe@manyfish.co.uk>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n   \n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n\n#include \"config.h\"\n\n#include <sys/types.h>\n\n#ifdef HAVE_STRING_H\n#include <string.h>\n#endif\n\n#include <stdio.h>\n#include <ctype.h> /* isdigit() for ne_parse_statusline */\n\n#ifdef NE_HAVE_ZLIB\n#include <zlib.h>\n#endif\n\n#ifdef HAVE_OPENSSL\n#include <openssl/opensslv.h>\n#endif\n\n#ifdef HAVE_GNUTLS\n#include <gnutls/gnutls.h>\n#endif\n\n/* libxml2: pick up the version string. */\n#if defined(HAVE_LIBXML)\n#include <libxml/xmlversion.h>\n#elif defined(HAVE_EXPAT) && !defined(HAVE_XMLPARSE_H)\n#include <expat.h>\n#endif\n\n#ifdef NE_HAVE_NTLM\n#include <ntlm.h>\n#endif\n\n#include \"ne_utils.h\"\n#include \"ne_string.h\" /* for ne_strdup */\n#include \"ne_dates.h\"\n\nint ne_debug_mask = 0;\nFILE *ne_debug_stream = NULL;\n\nvoid ne_debug_init(FILE *stream, int mask)\n{\n    ne_debug_stream = stream;\n    ne_debug_mask = mask;\n#if defined(HAVE_SETVBUF) && defined(_IONBF)\n    /* If possible, turn off buffering on the debug log.  this is very\n     * helpful if debugging segfaults. */\n    if (stream) setvbuf(stream, NULL, _IONBF, 0);\n#endif        \n}\n\nvoid ne_debug(int ch, const char *template, ...) \n{\n    va_list params;\n    if ((ch & ne_debug_mask) == 0) return;\n    fflush(stdout);\n    va_start(params, template);\n    vfprintf(ne_debug_stream, template, params);\n    va_end(params);\n    if ((ch & NE_DBG_FLUSH) == NE_DBG_FLUSH)\n\tfflush(ne_debug_stream);\n}\n\n#define NE_STRINGIFY(x) # x\n#define NE_EXPAT_VER(x,y,z) NE_STRINGIFY(x) \".\" NE_STRINGIFY(y) \".\" NE_STRINGIFY(z)\n\nstatic const char version_string[] = \"neon \" NEON_VERSION \": \" \n#ifdef NEON_IS_LIBRARY\n  \"Library build\"\n#else\n  \"Bundled build\"\n#endif\n#ifdef NE_HAVE_IPV6\n   \", IPv6\"\n#endif\n#ifdef HAVE_EXPAT\n  \", Expat\"\n/* expat >=1.95.2 exported the version */\n#ifdef XML_MAJOR_VERSION\n\" \" NE_EXPAT_VER(XML_MAJOR_VERSION, XML_MINOR_VERSION, XML_MICRO_VERSION)\n#endif\n#else /* !HAVE_EXPAT */\n#ifdef HAVE_LIBXML\n  \", libxml \" LIBXML_DOTTED_VERSION\n#endif /* HAVE_LIBXML */\n#endif /* !HAVE_EXPAT */\n#if defined(NE_HAVE_ZLIB) && defined(ZLIB_VERSION)\n  \", zlib \" ZLIB_VERSION\n#endif /* NE_HAVE_ZLIB && ... */\n#ifdef NE_HAVE_SOCKS\n   \", SOCKSv5\"\n#endif\n#ifdef NE_HAVE_LFS\n   \", LFS\"\n#endif\n#ifdef HAVE_OPENSSL\n#ifdef OPENSSL_VERSION_TEXT\n    \", \" OPENSSL_VERSION_TEXT\n#else\n   \"OpenSSL (unknown version)\"\n#endif /* OPENSSL_VERSION_TEXT */\n#ifdef NE_HAVE_TS_SSL\n    \" (thread-safe)\"\n#endif\n#endif /* HAVE_OPENSSL */\n#ifdef HAVE_GNUTLS\n    \", GNU TLS \" LIBGNUTLS_VERSION\n#endif /* HAVE_GNUTLS */\n#ifdef HAVE_SSPI\n    \", SSPI\"\n#endif /* HAVE_SSPI */\n#ifdef HAVE_PAKCHOIS\n    \", PKCS#11\"\n#endif\n#ifdef NE_HAVE_LIBPXY\n    \", libproxy\"\n#endif\n#ifdef NE_HAVE_NTLM\n    \", libntlm \" NTLM_VERSION\n#endif\n   \".\"\n;\n\nconst char *ne_version_string(void)\n{\n    return version_string;\n}\n\nconst char *ne_version_library(void)\n{\n    return NEON_VERSION;\n}\n\n#define LAST_COMPAT_ZERO_MINOR (27)\n\n#if NE_VERSION_MAJOR > 0\n#error update ne_version_match for 1.x compatibility\n#endif\n\nint ne_version_match(int major, int minor)\n{\n    return !\n        (major == 0\n         && (minor >= LAST_COMPAT_ZERO_MINOR && minor <= NE_VERSION_MINOR));\n}\n\nint ne_has_support(int feature)\n{\n    switch (feature) {\n#if defined(NE_HAVE_SSL) || defined(NE_HAVE_ZLIB) || defined(NE_HAVE_IPV6) \\\n    || defined(NE_HAVE_SOCKS) || defined(NE_HAVE_LFS) \\\n    || defined(NE_HAVE_TS_SSL) || defined(NE_HAVE_I18N) || defined(HAVE_SSPI) \\\n    || defined(NE_HAVE_GSSAPI) || defined(NE_HAVE_LIBPXY) || defined(NE_HAVE_NTLM)\n#ifdef NE_HAVE_SSL\n    case NE_FEATURE_SSL:\n#endif\n#ifdef NE_HAVE_ZLIB\n    case NE_FEATURE_ZLIB:\n#endif\n#ifdef NE_HAVE_IPV6\n    case NE_FEATURE_IPV6:\n#endif\n#ifdef NE_HAVE_SOCKS\n    case NE_FEATURE_SOCKS:\n#endif\n#ifdef NE_HAVE_LFS\n    case NE_FEATURE_LFS:\n#endif\n#ifdef NE_HAVE_TS_SSL\n    case NE_FEATURE_TS_SSL:\n#endif\n#ifdef NE_HAVE_I18N\n    case NE_FEATURE_I18N:\n#endif\n#ifdef HAVE_SSPI\n    case NE_FEATURE_SSPI:\n#endif\n#ifdef NE_HAVE_GSSAPI\n    case NE_FEATURE_GSSAPI:\n#endif\n#ifdef NE_HAVE_LIBPXY\n    case NE_FEATURE_LIBPXY:\n#endif\n#ifdef NE_HAVE_NTLM\n    case NE_FEATURE_NTLM:\n#endif\n        return 1;\n#endif /* NE_HAVE_* */\n    default:\n        return 0;\n    }\n}\n\n/* Lookup table - digit values=0-9, reason_phrase=0-10. */\n\n/* Generated with 'mktable status_line', do not alter here -- */\nstatic const unsigned char table_status_line[256] = {\n/* x00 */ 99, 99, 99, 99, 99, 99, 99, 99, 99, 10, 99, 99, 99, 99, 99, 99,\n/* x10 */ 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,\n/* x20 */ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,\n/* x30 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10, 10, 10,\n/* x40 */ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,\n/* x50 */ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,\n/* x60 */ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,\n/* x70 */ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 99,\n/* x80 */ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,\n/* x90 */ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,\n/* xA0 */ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,\n/* xB0 */ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,\n/* xC0 */ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,\n/* xD0 */ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,\n/* xE0 */ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,\n/* xF0 */ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10\n}; /* -- Generated code from 'mktable status_line' ends. */\n\n/* Strict parser per RFC9112§4:\n *\n *    status-line = HTTP-version SP status-code SP [ reason-phrase ]\n *  HTTP-version  = HTTP-name \"/\" DIGIT \".\" DIGIT\n * reason-phrase  = 1*( HTAB / SP / VCHAR / obs-text )\n */\nint ne_parse_statusline(const char *status_line, ne_status *st)\n{\n    const unsigned char *p = (const unsigned char *)status_line, *rp;\n    unsigned int major, minor, status_code, klass;\n\n    /* p => status-line */\n    if (strncmp((const char *)p, \"HTTP/\", 5) != 0)\n        return -1;\n\n    minor = major = 0;\n    p += 5;\n\n    /* X.Y */\n    if ((major = table_status_line[*p++]) > 9)\n        return -1;\n    if (*p++ != '.')\n        return -1;\n    if ((minor = table_status_line[*p++]) > 9)\n        return -1;\n\n    if (*p++ != ' ') return -1;\n\n    if ((klass = table_status_line[p[0]]) > 5 /* note 5xx maximum */\n        || table_status_line[p[1]] > 9 || table_status_line[p[2]] > 9\n        || p[3] != ' ')\n        return -1;\n\n    status_code = klass * 100 + table_status_line[p[1]] * 10\n        + table_status_line[p[2]];\n\n    rp = p += 4; /* p => [ reason-phrase ] */\n    while (table_status_line[*p] < 11) /* note this terminates for *p == '\\0' */\n        p++;\n\n    /* Fill in the results */\n    st->major_version = major;\n    st->minor_version = minor;\n    st->reason_phrase = ne_malloc(p - rp + 1);\n    ne_strnzcpy(st->reason_phrase, (const char *)rp, p - rp + 1);\n    ne_strclean(st->reason_phrase);\n    st->code = status_code;\n    st->klass = klass;\n    return 0;\n}\n"
  },
  {
    "path": "src/ne_utils.h",
    "content": "/* \n   HTTP utility functions\n   Copyright (C) 1999-2021, Joe Orton <joe@manyfish.co.uk>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n   \n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n\n#ifndef NE_UTILS_H\n#define NE_UTILS_H\n\n#include <sys/types.h>\n\n#include <stdarg.h>\n#include <stdio.h>\n\n#include \"ne_defs.h\"\n\n#ifdef NEON_TRIO\n#include <trio.h>\n#endif\n\nNE_BEGIN_DECLS\n\n/* Returns a human-readable library version string describing the\n * version and build information; for example:\n *    \"neon 0.2.0: Library build, OpenSSL support\" */\nconst char *ne_version_string(void);\n\n/* Returns the library version as a simple version string; for example:\n *    \"0.37.0\" */\nconst char *ne_version_library(void);\n\n/* Returns non-zero if neon library version is backwards-compatible with\n * ABI at given (major, minor). */\nint ne_version_match(int major, int minor);\n\n/* Feature codes: */\n#define NE_FEATURE_SSL (1) /* SSL/TLS support */\n#define NE_FEATURE_ZLIB (2) /* zlib compression in compress interface */\n#define NE_FEATURE_IPV6 (3) /* IPv6 is supported in resolver */\n#define NE_FEATURE_LFS (4) /* large file support */\n#define NE_FEATURE_SOCKS (5) /* SOCKSv5 support */\n#define NE_FEATURE_TS_SSL (6) /* Thread-safe SSL/TLS support */\n#define NE_FEATURE_I18N (7) /* i18n error message support */\n#define NE_FEATURE_SSPI (8) /* NTLM/Negotiate authentication protocol via SSPI */\n#define NE_FEATURE_GSSAPI (9) /* GSSAPI support. */\n#define NE_FEATURE_LIBPXY (10) /* System proxy support via libproxy. */\n#define NE_FEATURE_NTLM (11) /* NTLM authentication support via Libntlm. */\n\n/* Returns non-zero if library is built with support for the given\n * NE_FEATURE_* feature code 'code'. */\nint ne_has_support(int feature);\n\n/* Debugging macro to allow code to be optimized out if debugging is\n * disabled at build time. */\n#ifndef NE_DEBUGGING\n#define NE_DEBUG if (0) ne_debug\n#else /* DEBUGGING */\n#define NE_DEBUG ne_debug\n#endif /* DEBUGGING */\n\n/* Debugging masks. */\n#define NE_DBG_SOCKET (1<<0) /* raw socket */\n#define NE_DBG_HTTP (1<<1) /* HTTP request/response handling */\n#define NE_DBG_XML (1<<2) /* XML parser */\n#define NE_DBG_HTTPAUTH (1<<3) /* HTTP authentication (hiding credentials) */\n#define NE_DBG_HTTPPLAIN (1<<4) /* plaintext HTTP authentication */\n#define NE_DBG_LOCKS (1<<5) /* WebDAV locking */\n#define NE_DBG_XMLPARSE (1<<6) /* low-level XML parser */\n#define NE_DBG_HTTPBODY (1<<7) /* HTTP response body blocks */\n#define NE_DBG_SSL (1<<8) /* SSL/TLS */\n#define NE_DBG_FLUSH (1<<30) /* always flush debugging */\n\n/* Send debugging output to 'stream', for all of the given debug\n * channels.  To disable debugging, pass 'stream' as NULL and 'mask'\n * as 0. */\nvoid ne_debug_init(FILE *stream, int mask);\n\n/* The current debug mask and stream set by the last call to\n * ne_debug_init. */\nNE_VAR int ne_debug_mask;\nNE_VAR FILE *ne_debug_stream;\n\n/* Produce debug output if any of channels 'ch' is enabled for\n * debugging. */\nvoid ne_debug(int ch, const char *, ...) ne_attribute((format(printf, 2, 3)));\n\n/* Storing an HTTP status result */\ntypedef struct {\n    int major_version;\n    int minor_version;\n    int code; /* Status-Code value (100..599 inclusive) */\n    int klass; /* Class of Status-Code (1-5) */\n    char *reason_phrase;\n} ne_status;\n\n/* NB: couldn't use 'class' in ne_status because it would clash with\n * the C++ reserved word. */\n\n/* Parse 'status_line' using the RFC 9112 status-line grammar.\n * s->reason_phrase is malloc-allocated if non-NULL, and must be\n * free'd by the caller.  Returns 0 on success, in which case all\n * fields of '*s' will be set; or -1 on parse error, in which case\n * '*s' is unmodified. */\nint ne_parse_statusline(const char *status_line, ne_status *s);\n\nNE_END_DECLS\n\n#endif /* NE_UTILS_H */\n"
  },
  {
    "path": "src/ne_xml.c",
    "content": "/* \n   Wrapper interface to XML parser\n   Copyright (C) 1999-2021, Joe Orton <joe@manyfish.co.uk>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n   \n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n\n#include \"config.h\"\n\n#ifdef HAVE_STDLIB_H\n#include <stdlib.h>\n#endif\n#ifdef HAVE_STRING_H\n#include <string.h>\n#endif\n#ifdef HAVE_STRINGS_H\n#include <strings.h>\n#endif\n\n#include \"ne_internal.h\"\n\n#include \"ne_alloc.h\"\n#include \"ne_xml.h\"\n#include \"ne_utils.h\"\n#include \"ne_string.h\"\n\n#if defined(HAVE_EXPAT)\n/* expat support: */\n#ifdef HAVE_XMLPARSE_H\n#include \"xmlparse.h\"\n#else\n#include <expat.h>\n#endif\ntypedef XML_Char ne_xml_char;\n\n#if !defined(XML_MAJOR_VERSION)\n#define NEED_BOM_HANDLING\n#elif XML_MAJOR_VERSION < 2 && XML_MINOR_VERSION == 95 && XML_MICRO_VERSION < 2\n#define NEED_BOM_HANDLING\n#endif\n\n#elif defined(HAVE_LIBXML)\n/* libxml2 support: */\n#include <libxml/xmlversion.h>\n#include <libxml/parser.h>\ntypedef xmlChar ne_xml_char;\n\n#if LIBXML_VERSION < 20619\n/* 2.6.19 and earlier have broken BOM handling */\n#define NEED_BOM_HANDLING\n#endif\n#else /* not HAVE_LIBXML */\n#  error need an XML parser\n#endif /* not HAVE_EXPAT */\n\n/* Approx. one screen of text: */\n#define ERR_SIZE (2048)\n\nstruct handler {\n    ne_xml_startelm_cb *startelm_cb; /* start-element callback */\n    ne_xml_endelm_cb *endelm_cb; /* end-element callback */\n    ne_xml_cdata_cb *cdata_cb; /* character-data callback. */\n    void *userdata; /* userdata for the above. */\n    struct handler *next; /* next handler in stack. */\n};\n\n#ifdef HAVE_LIBXML\nstatic void sax_error(void *ctx, const char *msg, ...);\n#endif\n\nstruct element {\n    const ne_xml_char *nspace;\n    ne_xml_char *name;\n\n    int state; /* opaque state integer */\n    \n    /* Namespaces declared in this element */\n    ne_xml_char *default_ns; /* A default namespace */\n    struct namespace *nspaces; /* List of other namespace scopes */\n\n    struct handler *handler; /* Handler for this element */\n\n    struct element *parent; /* parent element, or NULL */    \n};\n\n/* We pass around a ne_xml_parser as the userdata in the parsing\n * library.  This maintains the current state of the parse and various\n * other bits and bobs. Within the parse, we store the current branch\n * of the tree, i.e., the current element and all its parents, up to\n * the root, but nothing other than that.  */\nstruct ne_xml_parser_s {\n    struct element *root; /* the root of the document */\n    struct element *current; /* current element in the branch */\n    struct handler *top_handlers; /* always points at the \n\t\t\t\t\t   * handler on top of the stack. */\n    int failure; /* zero whilst parse should continue */\n    int prune; /* if non-zero, depth within a dead branch */\n\n#ifdef NEED_BOM_HANDLING\n    int bom_pos;\n#endif\n\n#ifdef HAVE_EXPAT\n    XML_Parser parser;\n    char *encoding;\n#else\n    xmlParserCtxtPtr parser;\n#endif\n    char error[ERR_SIZE];\n};\n\n/* The callback handlers */\nstatic void start_element(void *userdata, const ne_xml_char *name, const ne_xml_char **atts);\nstatic void end_element(void *userdata, const ne_xml_char *name);\nstatic void char_data(void *userdata, const ne_xml_char *cdata, int len);\nstatic const char *resolve_nspace(const struct element *elm, \n                                  const char *prefix, size_t pfxlen);\n\n/* Linked list of namespace scopes */\nstruct namespace {\n    ne_xml_char *name;\n    ne_xml_char *uri;\n    struct namespace *next;\n};\n\n#ifdef HAVE_LIBXML\n\n/* Could be const as far as we care, but libxml doesn't want that */\nstatic xmlSAXHandler sax_handler = {\n    NULL, /* internalSubset */\n    NULL, /* isStandalone */\n    NULL, /* hasInternalSubset */\n    NULL, /* hasExternalSubset */\n    NULL, /* resolveEntity */\n    NULL, /* getEntity */\n    NULL, /* entityDecl */\n    NULL, /* notationDecl */\n    NULL, /* attributeDecl */\n    NULL, /* elementDecl */\n    NULL, /* unparsedEntityDecl */\n    NULL, /* setDocumentLocator */\n    NULL, /* startDocument */\n    NULL, /* endDocument */\n    start_element, /* startElement */\n    end_element, /* endElement */\n    NULL, /* reference */\n    char_data, /* characters */\n    NULL, /* ignorableWhitespace */\n    NULL, /* processingInstruction */\n    NULL, /* comment */\n    NULL, /* xmlParserWarning */\n    sax_error, /* xmlParserError */\n    sax_error, /* fatal error (never called by libxml2?) */\n    NULL, /* getParameterEntity */\n    char_data /* cdataBlock */\n};\n\n/* empty attributes array to mimic expat behaviour */\nstatic const char *const empty_atts[] = {NULL, NULL};\n\n/* macro for determining the attributes array to pass */\n#define PASS_ATTS(atts) (atts ? (const char **)(atts) : empty_atts)\n\n#if LIBXML_VERSION >= 21300\n/* Structured error handling from 2.13.x onwards. */\nstatic void error_handler(void *userdata, const xmlError *err)\n{\n    ne_xml_parser *p = userdata;\n\n    /* Catch any error, fatal error, or an unsupported encoding\n     * warning, to get equivalent error handling to expat. */\n    if (err->level == XML_ERR_ERROR || err->level == XML_ERR_FATAL\n        || (err->level == XML_ERR_WARNING && err->domain == XML_FROM_PARSER\n            && err->code == XML_ERR_UNSUPPORTED_ENCODING)) {\n        ne_snprintf(p->error, sizeof p->error,\n                    _(\"XML parse error: %s\"), err->message);\n\n        /* Strip trailing newlines. */\n        ne_shave(p->error, \"\\r\\n\");\n\n        NE_DEBUG(NE_DBG_XMLPARSE,\n                 \"xml: Structured error (domain %d level %d code %d): - '%s'\\n\",\n                 err->domain, err->level, err->code, p->error);\n        p->failure = 1;\n    }\n}\n#endif\n\n#else\n\n#define PASS_ATTS(atts) ((const char **)(atts))\n\n/* XML declaration callback for expat. */\nstatic void decl_handler(void *userdata,\n\t\t\t const XML_Char *version, const XML_Char *encoding, \n\t\t\t int standalone)\n{\n    ne_xml_parser *p = userdata;\n    if (encoding) p->encoding = ne_strdup(encoding);    \n}\n\n#endif /* HAVE_LIBXML */\n\nint ne_xml_currentline(ne_xml_parser *p) \n{\n#ifdef HAVE_EXPAT\n    return XML_GetCurrentLineNumber(p->parser);\n#else\n    return p->parser->input->line;\n#endif\n}\n\nconst char *ne_xml_doc_encoding(const ne_xml_parser *p)\n{\n#ifdef HAVE_LIBXML\n    return p->parser->encoding;\n#else\n    return p->encoding;\n#endif\n}\n\n/* The first character of the REC-xml-names \"NCName\" rule excludes\n * \"Digit | '.' | '-' | '_' | CombiningChar | Extender\"; the XML\n * parser will not enforce this rule in a namespace declaration since\n * it treats the entire attribute name as a REC-xml \"Name\" rule.  It's\n * too hard to check for all of CombiningChar | Digit | Extender here,\n * but the valid_ncname_ch1 macro catches some of the rest. */\n\n/* Return non-zero if 'ch' is an invalid start character for an NCName: */\n#define invalid_ncname_ch1(ch) ((ch) == '\\0' || strchr(\"-.0123456789\", (ch)) != NULL)\n\n/* Subversion repositories have been deployed which use property names\n * marshalled as NCNames including a colon character; these should\n * also be rejected but will be allowed for the time being. */\n#define invalid_ncname(xn) (invalid_ncname_ch1((xn)[0]))\n\n/* Extract the namespace prefix declarations from 'atts'. */\nstatic int declare_nspaces(ne_xml_parser *p, struct element *elm,\n                           const ne_xml_char **atts)\n{\n    int n;\n    \n    for (n = 0; atts && atts[n]; n += 2) {\n        if (strcmp(atts[n], \"xmlns\") == 0) {\n            /* New default namespace */\n            elm->default_ns = ne_strdup(atts[n+1]);\n        } else if (strncmp(atts[n], \"xmlns:\", 6) == 0) {\n            struct namespace *ns;\n            \n            /* Reject some invalid NCNames as namespace prefix, and an\n             * empty URI as the namespace URI */\n            if (invalid_ncname(atts[n] + 6) || atts[n+1][0] == '\\0') {\n                ne_snprintf(p->error, ERR_SIZE, \n                            (\"XML parse error at line %d: invalid namespace \"\n                             \"declaration\"), ne_xml_currentline(p));\n                return -1;\n            }\n\n            /* New namespace scope */\n            ns = ne_calloc(sizeof(*ns));\n            ns->next = elm->nspaces;\n            elm->nspaces = ns;\n            ns->name = ne_strdup(atts[n]+6); /* skip the xmlns= */\n            ns->uri = ne_strdup(atts[n+1]);\n        }\n    }\n    \n    return 0;\n}\n\n/* Expand an XML qualified name, which may include a namespace prefix\n * as well as the local part. */\nstatic int expand_qname(ne_xml_parser *p, struct element *elm,\n                        const ne_xml_char *qname)\n{\n    const ne_xml_char *pfx;\n\n    pfx = strchr(qname, ':');\n    if (pfx == NULL) {\n        struct element *e = elm;\n\n        /* Find default namespace; guaranteed to terminate as the root\n         * element always has default_ns=\"\". */\n        while (e->default_ns == NULL)\n            e = e->parent;\n        \n        elm->name = ne_strdup(qname);\n        elm->nspace = e->default_ns;\n    } else if (invalid_ncname(pfx + 1) || qname == pfx) {\n        ne_snprintf(p->error, ERR_SIZE, \n                    _(\"XML parse error at line %d: invalid element name\"), \n                    ne_xml_currentline(p));\n        return -1;\n    } else {\n        const char *uri = resolve_nspace(elm, qname, pfx-qname);\n\n\tif (uri) {\n\t    elm->name = ne_strdup(pfx+1);\n            elm->nspace = uri;\n\t} else {\n\t    ne_snprintf(p->error, ERR_SIZE, \n                        (\"XML parse error at line %d: undeclared namespace prefix\"),\n                        ne_xml_currentline(p));\n\t    return -1;\n\t}\n    }\n    return 0;\n}\n\n/* Called with the start of a new element. */\nstatic void start_element(void *userdata, const ne_xml_char *name,\n\t\t\t  const ne_xml_char **atts) \n{\n    ne_xml_parser *p = userdata;\n    struct element *elm;\n    struct handler *hand;\n    int state = NE_XML_DECLINE;\n\n    if (p->failure) return;\n    \n    if (p->prune) {\n        p->prune++;\n        return;\n    }\n\n    /* Create a new element */\n    elm = ne_calloc(sizeof *elm);\n    elm->parent = p->current;\n    p->current = elm;\n\n    if (declare_nspaces(p, elm, atts) || expand_qname(p, elm, name)) {\n        p->failure = 1;\n        return;\n    }\n\n    /* Find a handler which will accept this element (or abort the parse) */\n    for (hand = elm->parent->handler; hand && state == NE_XML_DECLINE;\n         hand = hand->next) {\n        elm->handler = hand;\n        state = hand->startelm_cb(hand->userdata, elm->parent->state,\n                                  elm->nspace, elm->name, PASS_ATTS(atts));\n    }\n\n    NE_DEBUG(NE_DBG_XML, \"XML: start-element (%d, {%s, %s}) => %d\\n\", \n             elm->parent->state, elm->nspace, elm->name, state);             \n    \n    if (state > 0)\n        elm->state = state;\n    else if (state == NE_XML_DECLINE)\n        /* prune this branch. */\n        p->prune++;\n    else /* state < 0 => abort parse  */\n        p->failure = state;\n}\n\n/* Destroys an element structure. */\nstatic void destroy_element(struct element *elm) \n{\n    struct namespace *this_ns, *next_ns;\n    ne_free(elm->name);\n    /* Free the namespaces */\n    this_ns = elm->nspaces;\n    while (this_ns != NULL) {\n\tnext_ns = this_ns->next;\n\tne_free(this_ns->name);\n\tne_free(this_ns->uri);\n\tne_free(this_ns);\n\tthis_ns = next_ns;\n    }\n    if (elm->default_ns)\n        ne_free(elm->default_ns);\n    ne_free(elm);\n}\n\n/* cdata SAX callback */\nstatic void char_data(void *userdata, const ne_xml_char *data, int len) \n{\n    ne_xml_parser *p = userdata;\n    struct element *elm = p->current;\n\n    if (p->failure || p->prune) return;\n    \n    if (elm->handler->cdata_cb) {\n        p->failure = elm->handler->cdata_cb(elm->handler->userdata, elm->state, data, len);\n        NE_DEBUG(NE_DBG_XML, \"XML: char-data (%d) returns %d\\n\", \n                 elm->state, p->failure);\n    }        \n}\n\n/* Called with the end of an element */\nstatic void end_element(void *userdata, const ne_xml_char *name) \n{\n    ne_xml_parser *p = userdata;\n    struct element *elm = p->current;\n\n    if (p->failure) return;\n\t\n    if (p->prune) {\n        if (p->prune-- > 1) return;\n    } else if (elm->handler->endelm_cb) {\n        p->failure = elm->handler->endelm_cb(elm->handler->userdata, elm->state,\n                                             elm->nspace, elm->name);\n        if (p->failure) {\n            NE_DEBUG(NE_DBG_XML, \"XML: end-element for %d failed with %d.\\n\", \n                     elm->state, p->failure);\n        }\n    }\n    \n    NE_DEBUG(NE_DBG_XML, \"XML: end-element (%d, {%s, %s})\\n\",\n             elm->state, elm->nspace, elm->name);\n\n    /* move back up the tree */\n    p->current = elm->parent;\n    p->prune = 0;\n\n    destroy_element(elm);\n}\n\n#if defined(HAVE_EXPAT) && XML_MAJOR_VERSION > 1\n/* Stop the parser if an entity declaration is hit. */\nstatic void entity_declaration(void *userData, const XML_Char *entityName,\n                              int is_parameter_entity, const XML_Char *value,\n                              int value_length, const XML_Char *base,\n                              const XML_Char *systemId, const XML_Char *publicId,\n                              const XML_Char *notationName)\n{\n    ne_xml_parser *parser = userData;\n    \n    NE_DEBUG(NE_DBG_XMLPARSE, \"XML: entity declaration [%s]. Failing.\\n\",\n             entityName);\n\n    XML_StopParser(parser->parser, XML_FALSE);\n}\n#elif defined(HAVE_EXPAT)\n/* A noop default_handler. */\nstatic void default_handler(void *userData, const XML_Char *s, int len)\n{\n}\n#endif\n\n/* Find a namespace definition for 'prefix' in given element, where\n * length of prefix is 'pfxlen'.  Returns the URI or NULL. */\nstatic const char *resolve_nspace(const struct element *elm, \n                                  const char *prefix, size_t pfxlen)\n{\n    const struct element *s;\n\n    /* Search up the tree. */\n    for (s = elm; s != NULL; s = s->parent) {\n\tconst struct namespace *ns;\n\t/* Iterate over defined spaces on this node. */\n\tfor (ns = s->nspaces; ns != NULL; ns = ns->next) {\n\t    if (strlen(ns->name) == pfxlen && \n\t\tmemcmp(ns->name, prefix, pfxlen) == 0)\n\t\treturn ns->uri;\n\t}\n    }\n\n    return NULL;\n}\n\nconst char *ne_xml_resolve_nspace(ne_xml_parser *parser, \n                                  const char *prefix, size_t length)\n{\n    if (prefix) {\n        return resolve_nspace(parser->current, prefix, length);\n    }\n    else {\n        struct element *e = parser->current;\n\n        while (e->default_ns == NULL)\n            e = e->parent;\n\n        return e->default_ns;\n    }\n}\n\nne_xml_parser *ne_xml_create(void) \n{\n    ne_xml_parser *p = ne_calloc(sizeof *p);\n    /* Placeholder for the root element */\n    p->current = p->root = ne_calloc(sizeof *p->root);\n    p->root->default_ns = \"\";\n    p->root->state = 0;\n    ne_strnzcpy(p->error, _(\"Unknown error\"), sizeof p->error);\n#ifdef HAVE_EXPAT\n    p->parser = XML_ParserCreate(NULL);\n    if (p->parser == NULL) {\n\tabort();\n    }\n    XML_SetElementHandler(p->parser, start_element, end_element);\n    XML_SetCharacterDataHandler(p->parser, char_data);\n    XML_SetUserData(p->parser, (void *) p);\n    XML_SetXmlDeclHandler(p->parser, decl_handler);\n\n    /* Prevent the \"billion laughs\" attack against expat by disabling\n     * internal entity expansion.  With 2.x, forcibly stop the parser\n     * if an entity is declared - this is safer and a more obvious\n     * failure mode.  With older versions, installing a noop\n     * DefaultHandler means that internal entities will be expanded as\n     * the empty string, which is also sufficient to prevent the\n     * attack. */\n#if XML_MAJOR_VERSION > 1\n    XML_SetEntityDeclHandler(p->parser, entity_declaration);\n#else\n    XML_SetDefaultHandler(p->parser, default_handler);\n#endif\n\n#else /* HAVE_LIBXML */\n    p->parser = xmlCreatePushParserCtxt(&sax_handler, \n\t\t\t\t\t(void *)p, NULL, 0, NULL);\n    if (p->parser == NULL) {\n\tabort();\n    }\n#if LIBXML_VERSION < 20602\n    p->parser->replaceEntities = 1;\n#else\n    /* Enable expansion of entities, and disable network access. */\n    xmlCtxtUseOptions(p->parser, XML_PARSE_NOENT | XML_PARSE_NONET);\n#endif\n\n#if LIBXML_VERSION >= 21300\n    xmlCtxtSetErrorHandler(p->parser, error_handler, p);\n#endif\n\n#endif /* HAVE_LIBXML || HAVE_EXPAT */\n    return p;\n}\n\nint ne_xml_set_encoding(ne_xml_parser *p, const char *encoding)\n{\n#ifdef HAVE_EXPAT\n    if (XML_SetEncoding(p->parser, encoding))\n        return 0;\n    return 1;\n#else\n    if (xmlCtxtResetPush(p->parser, NULL, 0, NULL, encoding)) {\n        return 1;\n    }\n    /* For libxml 2.13+ the unknown encoding is raised via the\n     * structured error log handler, which set p->failure.\n     * See https://github.com/notroj/neon/issues/217 */\n    return p->failure;\n#endif\n}\n\nvoid ne_xml_push_handler(ne_xml_parser *p,\n\t\t\t ne_xml_startelm_cb *startelm_cb, \n\t\t\t ne_xml_cdata_cb *cdata_cb, \n\t\t\t ne_xml_endelm_cb *endelm_cb,\n\t\t\t void *userdata)\n{\n    struct handler *hand = ne_calloc(sizeof(struct handler));\n\n    hand->startelm_cb = startelm_cb;\n    hand->cdata_cb = cdata_cb;\n    hand->endelm_cb = endelm_cb;\n    hand->userdata = userdata;\n\n    /* If this is the first handler registered, update the\n     * base pointer too. */\n    if (p->top_handlers == NULL) {\n\tp->root->handler = hand;\n\tp->top_handlers = hand;\n    } else {\n\tp->top_handlers->next = hand;\n\tp->top_handlers = hand;\n    }\n}\n\nint ne_xml_parse_v(void *userdata, const char *block, size_t len) \n{\n    ne_xml_parser *p = userdata;\n    return ne_xml_parse(p, (const ne_xml_char *)block, len);\n}\n\n#define BOM_UTF8 \"\\xEF\\xBB\\xBF\" /* UTF-8 BOM */\n\nint ne_xml_parse(ne_xml_parser *p, const char *block, size_t len) \n{\n    int ret, flag;\n    /* duck out if it's broken */\n    if (p->failure) {\n\tNE_DEBUG(NE_DBG_XMLPARSE, \"XML: Failed; ignoring %\" NE_FMT_SIZE_T \n                 \" bytes.\\n\", len);\n\treturn p->failure;\n    }\n    if (len == 0) {\n\tflag = -1;\n\tblock = \"\";\n\tNE_DEBUG(NE_DBG_XMLPARSE, \"XML: End of document.\\n\");\n    } else {\t\n\tNE_DEBUG(NE_DBG_XMLPARSE, \"XML: Parsing %\" NE_FMT_SIZE_T \" bytes.\\n\", len);\n\tflag = 0;\n    }\n\n#ifdef NEED_BOM_HANDLING\n    if (p->bom_pos < 3) {\n        NE_DEBUG(NE_DBG_XMLPARSE, \"Checking for UTF-8 BOM.\\n\");\n        while (len > 0 && p->bom_pos < 3 && \n               block[0] == BOM_UTF8[p->bom_pos]) {\n            block++;\n            len--;\n            p->bom_pos++;\n        }\n        if (len == 0)\n            return 0;\n        if (p->bom_pos == 0) {\n            p->bom_pos = 3; /* no BOM */\n        } else if (p->bom_pos > 0 && p->bom_pos < 3) {\n            ne_strnzcpy(p->error, _(\"Invalid Byte Order Mark\"), sizeof p->error);\n            return p->failure = 1;\n        }\n    }\n#endif\n\n    /* Note, don't write a parser error if p->failure, since an error\n     * will already have been written in that case. */\n#ifdef HAVE_EXPAT\n    ret = XML_Parse(p->parser, block, len, flag);\n    NE_DEBUG(NE_DBG_XMLPARSE, \"XML: XML_Parse returned %d\\n\", ret);\n    if (ret == 0 && p->failure == 0) {\n\tne_snprintf(p->error, ERR_SIZE,\n\t\t    \"XML parse error at line %\" NE_FMT_XML_SIZE \": %s\", \n\t\t    XML_GetCurrentLineNumber(p->parser),\n\t\t    XML_ErrorString(XML_GetErrorCode(p->parser)));\n\tp->failure = 1;\n        NE_DEBUG(NE_DBG_XMLPARSE, \"XML: Parse error: %s\\n\", p->error);\n    }\n#else\n    ret = xmlParseChunk(p->parser, block, len, flag);\n    NE_DEBUG(NE_DBG_XMLPARSE, \"XML: xmlParseChunk returned %d\\n\", ret);\n    /* Parse errors are normally caught by the sax_error() callback,\n     * which clears p->valid. */\n    if (p->parser->errNo && p->failure == 0) {\n\tne_snprintf(p->error, ERR_SIZE, \"XML parse error at line %d\", \n\t\t    ne_xml_currentline(p));\n\tp->failure = 1;\n        NE_DEBUG(NE_DBG_XMLPARSE, \"XML: Parse error: %s\\n\", p->error);\n    }\n#endif\n    return p->failure;\n}\n\nint ne_xml_failed(ne_xml_parser *p)\n{\n    return p->failure;\n}\n\nvoid ne_xml_destroy(ne_xml_parser *p) \n{\n    struct element *elm, *parent;\n    struct handler *hand, *next;\n\n    /* Free up the handlers on the stack: the root element has the\n     * pointer to the base of the handler stack. */\n    for (hand = p->root->handler; hand!=NULL; hand=next) {\n\tnext = hand->next;\n\tne_free(hand);\n    }\n\n    /* Clean up remaining elements */\n    for (elm = p->current; elm != p->root; elm = parent) {\n\tparent = elm->parent;\n\tdestroy_element(elm);\n    }\n\n    /* free root element */\n    ne_free(p->root);\n\n#ifdef HAVE_EXPAT\n    XML_ParserFree(p->parser);\n    if (p->encoding) ne_free(p->encoding);\n#else\n    xmlFreeParserCtxt(p->parser);\n#endif\n\n    ne_free(p);\n}\n\nvoid ne_xml_set_error(ne_xml_parser *p, const char *msg)\n{\n    ne_snprintf(p->error, ERR_SIZE, \"%s\", msg);\n}\n\n#ifdef HAVE_LIBXML\nstatic void sax_error(void *ctx, const char *msg, ...)\n{\n    ne_xml_parser *p = ctx;\n    va_list ap;\n    char buf[1024];\n\n    va_start(ap, msg);\n    ne_vsnprintf(buf, 1024, msg, ap);\n    va_end(ap);\n\n    NE_DEBUG(NE_DBG_XMLPARSE, \"xml: Error thrown: %s\\n\", buf);\n    if (p->failure == 0) {\n        ne_snprintf(p->error, ERR_SIZE, \n                    _(\"XML parse error at line %d: %s\"),\n                    p->parser->input->line, buf);\n        p->failure = 1;\n    }\n}\n#endif\n\nconst char *ne_xml_get_error(ne_xml_parser *p)\n{\n    return p->error;\n}\n\nconst char *\nne_xml_get_attr(ne_xml_parser *p, const char **attrs, \n\t\tconst char *nspace, const char *name)\n{\n    int n;\n\n    for (n = 0; attrs[n] != NULL; n += 2) {\n\tconst char *pnt = strchr(attrs[n], ':');\n\n\tif (!nspace && !pnt && strcmp(attrs[n], name) == 0) {\n\t    return attrs[n+1];\n\t} else if (nspace && pnt) {\n\t    /* If a namespace is given, and the local part matches,\n\t     * then resolve the namespace and compare that too. */\n\t    if (strcmp(pnt + 1, name) == 0) {\n\t\tconst char *uri = resolve_nspace(p->current, \n\t\t\t\t\t\t attrs[n], pnt - attrs[n]);\n\t\tif (uri && strcmp(uri, nspace) == 0)\n\t\t    return attrs[n+1];\n\t    }\n\t}\n    }\n\n    return NULL;\n}\n\nint ne_xml_mapid(const struct ne_xml_idmap map[], size_t maplen,\n                 const char *nspace, const char *name)\n{\n    size_t n;\n    \n    for (n = 0; n < maplen; n++)\n        if (strcmp(name, map[n].name) == 0 &&\n            strcmp(nspace, map[n].nspace) == 0)\n            return map[n].id;\n    \n    return 0;\n}\n"
  },
  {
    "path": "src/ne_xml.h",
    "content": "/* \n   neon XML parser interface\n   Copyright (C) 1999-2021, Joe Orton <joe@manyfish.co.uk>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n   \n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n\n#ifndef NE_XML_H\n#define NE_XML_H\n\n#include <sys/types.h> /* for size_t */\n\n#include \"ne_defs.h\"\n\nNE_BEGIN_DECLS\n\n/* The neon XML interface filters a streamed XML tree through a stack\n * of SAX \"handlers\".  A handler is made up of three callbacks\n * (start-element, char-data, end-element).  Each start-element event\n * is passed to each handler in the stack in turn until one until one\n * accepts the element.  This handler then receives subsequent\n * char-data and end-element events for the element.\n *\n * For each new start-element event, the search up the handler stack\n * begins with the handler for the parent element (for the root\n * element, at the base of the stack).\n *\n * For each accepted element, a \"state\" integer is stored, which is\n * passed to the corresponding char-data and end-element callbacks for\n * the element.  This integer is also passed to the start-element\n * callback of child elements so they can determine context.\n *\n * If no handler in the stack accepts a particular element, it (and\n * its children, if any) is ignored. */\n\n#define NE_XML_DECLINE (0)\n#define NE_XML_ABORT (-1)\n\n/* A start-element callback for element with given namespace/name.\n * The callback may return:\n *   <0  =>  abort the parse (NE_XML_ABORT)\n *    0  =>  decline this element (NE_XML_DECLINE)\n *   >0  =>  accept this element; value is state for this element.\n *\n * The 'parent' integer is the state returned by the handler of the \n * parent element.   The attributes array gives name/value pairs\n * in atts[n] and atts[n+1] from n=0 up to atts[n]==NULL. */\ntypedef int ne_xml_startelm_cb(void *userdata, int parent,\n                               const char *nspace, const char *name,\n                               const char **atts);\n\n/* state for the root element */\n#define NE_XML_STATEROOT (0)\n\n/* Character data callback; may return non-zero to abort the parse. */\ntypedef int ne_xml_cdata_cb(void *userdata, int state,\n                            const char *cdata, size_t len);\n/* End element callback; may return non-zero to abort the parse. */\ntypedef int ne_xml_endelm_cb(void *userdata, int state, \n                             const char *nspace, const char *name);\n\ntypedef struct ne_xml_parser_s ne_xml_parser;\n\n/* Create an XML parser. */\nne_xml_parser *ne_xml_create(void);\n\n/* Set character encoding 'encoding' for the parser 'p'. Returns\n * zero on success, non-zero on failure. */\nint ne_xml_set_encoding(ne_xml_parser *p, const char *encoding);\n\n/* Push a new handler on the stack of parser 'p'. 'cdata' and/or\n * 'endelm' may be NULL; startelm must be non-NULL. */\nvoid ne_xml_push_handler(ne_xml_parser *p,\n                         ne_xml_startelm_cb *startelm, \n                         ne_xml_cdata_cb *cdata,\n                         ne_xml_endelm_cb *endelm,\n                         void *userdata);\n\n/* ne_xml_failed returns non-zero if there was an error during\n * parsing, or zero if the parse completed successfully.  The return\n * value is equal to that of the last ne_xml_parse() call for this\n * parser object. */\nint ne_xml_failed(ne_xml_parser *p);\n\n/* Set error string for parser.  (The string may be truncated\n * internally). */\nvoid ne_xml_set_error(ne_xml_parser *p, const char *msg);\n\n/* Return the error string (and never NULL).  After ne_xml_failed\n * returns >0, this will describe the parse error.  Otherwise it will\n * be a default error string. */\nconst char *ne_xml_get_error(ne_xml_parser *p);\n\n/* Parse the given block of input of length len.  Parser must be\n * called with len=0 to signify the end of the document (for that\n * case, the block argument is ignored).  Returns zero on success, or\n * non-zero on error: for an XML syntax error, a positive number is\n * returned; if parsing is aborted by a caller-supplied callback, that\n * callback's return value is returned. */\nint ne_xml_parse(ne_xml_parser *p, const char *block, size_t len);\n\n/* As ne_xml_parse, casting (ne_xml_parser *)userdata internally.\n * (This function can be passed to ne_add_response_body_reader) */\nint ne_xml_parse_v(void *userdata, const char *block, size_t len);\n\n/* Return current line of document during parsing or after parsing is\n * complete. */\nint ne_xml_currentline(ne_xml_parser *p);\n\n/* From a start_element callback which was passed 'attrs' using given\n * parser, return attribute of given name and namespace.  If nspace is\n * NULL, no namespace resolution is performed.  Note that this call is\n * context-specific; if called outside a start_element callback,\n * behaviour is undefined. */\nconst char *ne_xml_get_attr(ne_xml_parser *parser,\n\t\t\t    const char **attrs, const char *nspace, \n\t\t\t    const char *name);\n\n/* From a start_element callback, resolve a given XML Namespace\n * prefix, if defined.  Given a non-NULL prefix, returns the namespace\n * URI which corresponds to the prefix 'prefix' (of length 'length'),\n * or NULL if no such namespace prefix is defined.  Given a NULL\n * prefix, returns the default namespace URI or the empty string if\n * none is defined.  Note that this call is context-specific; if\n * called outside a start_element callback, behaviour is undefined. */\nconst char *ne_xml_resolve_nspace(ne_xml_parser *parser, \n                                  const char *prefix, size_t length);\n\n/* Return the encoding of the document being parsed as provided by the\n * declaration. May return NULL if no encoding is defined in the\n * declaration, or if the XML declaration has not yet been parsed. */\nconst char *ne_xml_doc_encoding(const ne_xml_parser *p);\n\n/* Destroy the parser object. */\nvoid ne_xml_destroy(ne_xml_parser *p);\n\n/* A utility interface for mapping {nspace, name} onto an integer. */\nstruct ne_xml_idmap {\n    const char *nspace, *name;\n    int id;\n};\n\n/* Return the size of an idmap array */\n#define NE_XML_MAPLEN(map) (sizeof(map) / sizeof(struct ne_xml_idmap))\n\n/* Return the 'id' corresponding to {nspace, name}, or zero. */\nint ne_xml_mapid(const struct ne_xml_idmap map[], size_t maplen,\n                 const char *nspace, const char *name);\n\n/* media type, appropriate for adding to a Content-Type header */\n#define NE_XML_MEDIA_TYPE \"application/xml\"\n\nNE_END_DECLS\n\n#endif /* NE_XML_H */\n"
  },
  {
    "path": "src/ne_xmlreq.c",
    "content": "/* \n   XML/HTTP response handling\n   Copyright (C) 2004-2021, Joe Orton <joe@manyfish.co.uk>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n   \n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n\n#include \"config.h\"\n\n#include <string.h>\n#include <stdlib.h>\n\n#include \"ne_internal.h\"\n#include \"ne_xmlreq.h\"\n#include \"ne_basic.h\"\n#include \"ne_string.h\"\n\n/* Handle an XML response parse error, setting session error string\n * and closing the connection. */\nstatic int parse_error(ne_request *req, ne_xml_parser *parser)\n{\n    ne_session *const sess = ne_get_session(req);\n\n    ne_set_error(sess, _(\"Could not parse response: %s\"),\n                 ne_xml_get_error(parser));\n    NE_DEBUG(NE_DBG_XML, \"xmlreq: Parse failed, set error: %s\\n\",\n             ne_get_error(sess));\n    ne_close_connection(sess);\n    return NE_ERROR;\n}\n\nint ne_xml_parse_response(ne_request *req, ne_xml_parser *parser)\n{\n    char buf[8000];\n    ssize_t bytes;\n    int ret = 0;\n\n    while ((bytes = ne_read_response_block(req, buf, sizeof buf)) > 0) {\n        ret = ne_xml_parse(parser, buf, bytes);\n        if (ret)\n            return parse_error(req, parser);\n    }\n\n    if (bytes == 0) {\n        /* Tell the parser that end of document was reached: */\n        if (ne_xml_parse(parser, NULL, 0) == 0)\n            return NE_OK;\n        else\n            return parse_error(req, parser);\n    } else {\n        return NE_ERROR;\n    }    \n}\n\n/* Returns non-zero if given content-type is an XML media type,\n * following the RFC 7303 rules. */\nstatic int media_type_is_xml(const ne_content_type *ctype)\n{\n    size_t stlen;\n\n    return \n        (ne_strcasecmp(ctype->type, \"text\") == 0\n         && ne_strcasecmp(ctype->subtype, \"xml\") == 0)\n        || (ne_strcasecmp(ctype->type, \"application\") == 0\n            && ne_strcasecmp(ctype->subtype, \"xml\") == 0)\n        || ((stlen = strlen(ctype->subtype)) > 4\n            && ne_strcasecmp(ctype->subtype + stlen - 4, \"+xml\") == 0);\n}\n\nint ne_xml_dispatch_request(ne_request *req, ne_xml_parser *parser)\n{\n    return ne_xml_dispatchif_request(req, parser, ne_accept_2xx, NULL);\n}\n\nint ne_xml_dispatchif_request(ne_request *req, ne_xml_parser *parser,\n                              ne_accept_response acpt, void *userdata)\n{\n    int ret;\n\n    do {\n        int parseit = 0;\n\n        ret = ne_begin_request(req);\n        if (ret) break;\n        \n        if (acpt(userdata, req, ne_get_status(req))) {\n            ne_content_type ctype;\n\n            if (ne_get_content_type(req, &ctype) == 0) {\n                parseit = media_type_is_xml(&ctype);\n\n                if (parseit && ctype.charset) {\n                    NE_DEBUG(NE_DBG_XML, \"xmlreq: Using charset '%s'\\n\",\n                             ctype.charset);\n                    if (ne_xml_set_encoding(parser, ctype.charset)) {\n                        ne_free(ctype.value);\n                        return parse_error(req, parser);\n                    }\n                }\n                ne_free(ctype.value);\n            }\n\n            NE_DEBUG(NE_DBG_XML, \"xmlreq: Accepted response status %d, \"\n                     \"will%s parse.\\n\", ne_get_status(req)->code,\n                     parseit ? \"\" : \" not\");\n        }\n\n        if (parseit)\n            ret = ne_xml_parse_response(req, parser);\n        else\n            ret = ne_discard_response(req);\n        \n        if (ret == NE_OK)\n            ret = ne_end_request(req);\n    } while (ret == NE_RETRY);\n\n    return ret;\n}\n\n"
  },
  {
    "path": "src/ne_xmlreq.h",
    "content": "/* \n   XML/HTTP response handling\n   Copyright (C) 2004-2021, Joe Orton <joe@manyfish.co.uk>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n   \n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n\n#ifndef NE_XMLREQ_H\n#define NE_XMLREQ_H\n\n#include \"ne_request.h\"\n#include \"ne_xml.h\"\n\nNE_BEGIN_DECLS\n\n/* Read the HTTP response body using calls to ne_read_response_block\n * (so must be enclosed by ne_begin_request/ne_end_request calls), and\n * parse it as an XML document, using the given parser.  Returns NE_*\n * error codes.  If an XML parse error occurs, the session error\n * string is set to the XML parser's error string, and NE_ERROR is\n * returned. */\nint ne_xml_parse_response(ne_request *req, ne_xml_parser *parser);\n\n/* Dispatch the HTTP request, parsing the response body as an XML\n * document using the given parser, if the response status class is\n * 2xx and an XML media type is specified for the response entity.  If\n * a non-2xx response code is given, or a non-XML media type is\n * specified, then the response body will be silently discarded.\n *\n * Returns NE_* error codes.  If an XML parse error occurs, the\n * session error string is set to the XML parser's error string, and\n * NE_ERROR is returned. */\nint ne_xml_dispatch_request(ne_request *req, ne_xml_parser *parser);\n\n/* Dispatch the HTTP request, conditionally parsing the response body\n * as an XML document using the given parser, if both the acceptor\n * callback 'acpt' returns non-zero, and an XML media type is\n * specified for the response entity.  If the acceptor callback\n * returns zero, or a non-XML media type is specified, then the\n * response body will be silently discarded.\n *\n * Returns NE_* error codes. If the response body is parsed and an XML\n * parse error occurs, the session error string is set to the XML\n * parser's error string, and NE_ERROR is returned. */\nint ne_xml_dispatchif_request(ne_request *req, ne_xml_parser *parser,\n                              ne_accept_response acpt, void *userdata);\n\nNE_END_DECLS\n\n#endif /* NE_XMLREQ_H */\n"
  },
  {
    "path": "src/neon.def",
    "content": ";  Listing for exporting symbols from the libneon DLL\n;  Copyright (C) 2003-2022, Joe Orton <joe@manyfish.co.uk>\n;\n;  This library is free software; you can redistribute it and/or\n;  modify it under the terms of the GNU Library General Public\n;  License as published by the Free Software Foundation; either\n;  version 2 of the License, or (at your option) any later version.\n;\n;  This library is distributed in the hope that it will be useful,\n;  but WITHOUT ANY WARRANTY; without even the implied warranty of\n;  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n;  Library General Public License for more details.\n;\n;  You should have received a copy of the GNU Library General Public\n;  License along with this library; if not, write to the Free\n;  Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n;  MA 02111-1307, USA\n\nEXPORTS\nne_accept_2xx\nne_accept_always\nne_add_request_header\nne_add_response_body_reader\nne_begin_request\nne_discard_response\nne_end_request\nne_get_request_flag\nne_get_request_private\nne_get_response_header\nne_get_session\nne_get_session_private\nne_get_status\nne_print_request_header\nne_read_response_block\nne_read_response_to_fd\nne_request_create\nne_request_destroy\nne_request_dispatch\nne_response_header_iterate\nne_set_request_body_buffer\nne_set_request_body_fd\nne_set_request_body_provider\nne_set_request_flag\nne_set_request_private\nne_close_connection\nne_fill_proxy_uri\nne_fill_server_uri\nne_get_error\nne_get_scheme\nne_get_server_hostport\nne_get_session_flag\nne_hook_close_conn\nne_hook_create_request\nne_hook_destroy_request\nne_hook_destroy_session\nne_hook_post_headers\nne_hook_post_send\nne_hook_pre_send\nne_session_create\nne_session_destroy\nne_session_proxy\nne_session_socks_proxy\nne_session_system_proxy\nne_set_addrlist\nne_set_addrlist2\nne_set_connect_timeout\nne_set_error\nne_set_localaddr\nne_set_notifier\nne_set_progress\nne_set_read_timeout\nne_set_session_flag\nne_set_session_private\nne_set_useragent\nne_ssl_cert_validity\nne_ssl_provide_clicert\nne_ssl_set_verify\nne_ssl_trust_cert\nne_unhook_close_conn\nne_unhook_create_request\nne_unhook_destroy_request\nne_unhook_destroy_session\nne_unhook_post_headers\nne_unhook_post_send\nne_unhook_pre_send\nne_version_pre_http11\nne_add_depth_header\nne_copy\nne_delete\nne_get\nne_get_content_type\nne_getmodtime\nne_get_range\nne_mkcol\nne_move\nne_options\nne_options2\nne_post\nne_put\nne_base64\nne_buffer_altered\nne_buffer_append\nne_buffer_clear\nne_buffer_concat\nne_buffer_create\nne_buffer_destroy\nne_buffer_finish\nne_buffer_grow\nne_buffer_ncreate\nne_buffer_qappend\nne_buffer_snprintf\nne_buffer_zappend\nne_concat\nne_qtoken\nne_shave\nne_snprintf\nne_strcasecmp\nne_strclean\nne_strerror\nne_strhash\nne_strncasecmp\nne_strnqdup\nne_strparam\nne_token\nne_tolower_array\nne_unbase64\nne_vsnprintf\nne_path_childof\nne_path_compare\nne_path_escape\nne_path_escapef\nne_path_has_trailing_slash\nne_path_parent\nne_path_unescape\nne_uri_cmp\nne_uri_copy\nne_uri_defaultport\nne_uri_free\nne_uri_parse\nne_uri_resolve\nne_uri_unparse\nne_asctime_parse\nne_httpdate_parse\nne_iso8601_parse\nne_rfc1036_parse\nne_rfc1123_date\nne_rfc1123_parse\nne_calloc\nne_malloc\nne_oom_callback\nne_realloc\nne_strdup\nne_strndup\nne_ascii_to_md5\nne_md5_create_ctx\nne_md5_destroy_ctx\nne_md5_dup_ctx\nne_md5_finish_ascii\nne_md5_finish_ctx\nne_md5_process_block\nne_md5_process_bytes\nne_md5_read_ctx\nne_md5_reset_ctx\nne_md5_stream\nne_md5_to_ascii\nne_debug\nne_debug_mask DATA\nne_debug_init\nne_debug_stream DATA\nne_has_support\nne_parse_statusline\nne_version_match\nne_version_string\nne_addr_canonical\nne_addr_destroy\nne_addr_error\nne_addr_first\nne_addr_next\nne_addr_resolve\nne_addr_result\nne_iaddr_cmp\nne_iaddr_free\nne_iaddr_make\nne_iaddr_parse\nne_iaddr_print\nne_iaddr_raw\nne_iaddr_reverse\nne_iaddr_typeof\nne_sock_accept\nne_sock_accept_ssl\nne_sock_block\nne_sock_cipher\nne_sock_close\nne_sock_connect\nne_sock_connect_ssl\nne_sock_connect_timeout\nne_sock_create\nne_sock_error\nne_sock_exit\nne_sock_fd\nne_sock_fullread\nne_sock_fullwrite\nne_sock_fullwritev\nne_sock_init\nne_sock_peek\nne_sock_peer\nne_sock_prebind\nne_sock_read\nne_sock_readline\nne_sock_read_timeout\nne_sock_sessid\nne_sock_set_error\nne_sock_shutdown\nne_add_auth\nne_add_proxy_auth\nne_add_server_auth\nne_forget_auth\nne_set_proxy_auth\nne_set_server_auth\nne_redirect_location\nne_redirect_register\nne_decompress_destroy\nne_decompress_reader\nne_i18n_init\nne_ssl_pkcs11_nss_provider_init\nne_ssl_pkcs11_provider_destroy\nne_ssl_pkcs11_provider_init\nne_ssl_pkcs11_provider_pin\nne_ssl_set_pkcs11_provider\nne_sock_proxy\nne_207_create\nne_207_destroy\nne_207_get_current_propstat\nne_207_get_current_response\nne_207_set_flags\nne_207_set_propstat_handlers\nne_207_set_response_handlers\nne_accept_207\nne_simple_request\nne_xml_create\nne_xml_currentline\nne_xml_destroy\nne_xml_doc_encoding\nne_xml_failed\nne_xml_get_attr\nne_xml_get_error\nne_xml_mapid\nne_xml_parse\nne_xml_parse_v\nne_xml_push_handler\nne_xml_resolve_nspace\nne_xml_set_error\nne_propfind_allprop\nne_propfind_create\nne_propfind_current_private\nne_propfind_destroy\nne_propfind_get_parser\nne_propfind_get_request\nne_propfind_named\nne_propfind_set_private\nne_propnames\nne_proppatch\nne_propset_iterate\nne_propset_lang\nne_propset_private\nne_propset_status\nne_propset_value\nne_simple_propfind\nne_lock\nne_lock_copy\nne_lock_create\nne_lock_destroy\nne_lock_discover\nne_lock_free\nne_lock_refresh\nne_lockstore_add\nne_lockstore_create\nne_lockstore_destroy\nne_lockstore_findbyuri\nne_lockstore_first\nne_lockstore_next\nne_lockstore_register\nne_lockstore_remove\nne_lock_using_parent\nne_lock_using_resource\nne_unlock\nne_xml_dispatch_request\nne_xml_parse_response\nne_acl_set\nne_acl3744_set\nne_ssl_cert_cmp\nne_ssl_cert_digest\nne_ssl_cert_export\nne_ssl_cert_free\nne_ssl_cert_hdigest\nne_ssl_cert_identity\nne_ssl_cert_import\nne_ssl_cert_issuer\nne_ssl_cert_read\nne_ssl_cert_signedby\nne_ssl_cert_subject\nne_ssl_cert_validity_time\nne_ssl_cert_write\nne_ssl_clicert_decrypt\nne_ssl_clicert_encrypted\nne_ssl_clicert_free\nne_ssl_clicert_import\nne_ssl_clicert_name\nne_ssl_clicert_owner\nne_ssl_clicert_read\nne_ssl_context_create\nne_ssl_context_destroy\nne_ssl_context_get_flag\nne_ssl_context_keypair\nne_ssl_context_set_flag\nne_ssl_context_set_verify\nne_ssl_context_trustcert\nne_ssl_dname_cmp\nne_ssl_readable_dname\nne_ssl_set_clicert\nne_ssl_trust_default_ca\nne_vstrhash\n"
  },
  {
    "path": "src/neon.vers",
    "content": "# GNU linker version script for neon.\n# All symbols in <= 0.28.x use default unversioned.\n\nNEON_0_29 {\n    ne_iaddr_raw;\n    ne_sock_writev;\n    ne_sock_fullwritev;\n    ne_sock_set_error;\n    ne_sock_proxy;\n    ne_session_system_proxy;\n    ne_session_socks_proxy;\n    ne_acl3744_set;\n    ne_buffer_qappend;\n    ne_strnqdup;\n};\n\nNEON_0_30 {\n    ne_ssl_clicert_import;\n    ne_addr_canonical;\n    ne_ssl_context_get_flag;\n    ne_set_addrlist2;\n};\n\nNEON_0_31 {\n    ne_path_escapef;\n    ne_207_set_flags;\n};\n\nNEON_0_32 {\n    ne_strhash;\n    ne_vstrhash;\n    ne_strparam;\n    ne_add_auth;\n    ne_ssl_cert_hdigest;\n    ne_sock_shutdown;\n};\n\nNEON_0_33 {\n    ne_add_interim_handler;\n    ne_putbuf;\n};\n\nNEON_0_34 {\n    ne_get_response_location;\n    ne_get_request_target;\n    ne_iaddr_set_scope;\n    ne_iaddr_get_scope;\n    ne_ssl_context_set_versions;\n    ne_ssl_set_protovers;\n    ne_ssl_proto_name;\n    ne_sock_getproto;\n};\n\nNEON_0_35 {\n    ne_strhextoul;\n    ne_get_response_retry_after;\n    ne_ssl_clicert_fromuri;\n};\n\nNEON_0_36 {\n    ne_xml_set_encoding;\n    ne_xml_dispatchif_request;\n    ne_getbuf;\n    ne_read_response_to_buffer;\n};\n\nNEON_0_37 {\n    ne_strlower;\n    ne_strupper;\n    ne_mknonce;\n    ne_ssl_clicert_copy;\n    ne_ssl_context_set_clicert;\n    ne_ssl_context_set_ccprovide;\n    ne_ssl_context_trustdefca;\n    ne_ssl_check_certificate;\n    ne_sock_getcert;\n    ne_sock_handshake;\n    ne_response_trailer_iterate;\n    ne_get_response_trailer;\n    ne_version_library;\n    ne_iaddr_put;\n};\n"
  },
  {
    "path": "test/.gdbinit",
    "content": "handle SIGPIPE noprint pass nostop\nhandle SIGUSR1 print pass nostop\n"
  },
  {
    "path": "test/.gitignore",
    "content": "/tests\n/*-tests\n/Makefile\n/request\n/*.log*\n/server\n/regress\n/compress\n/*.gz\n/*.lo\n/*.tmp\n/.libs\n/acl\n/oldacl\n/acl3744\n/auth\n/lock\n/basic\n/ssl\n/xml\n/stubs\n/twooh7\n/ca\n/ca-stamp\n/ssigned.pem\n/wildcard.*\n/*.cert\n/*.csr\n/fqdn.pem\n/wrongcn.pem\n/socket\n/redirect\n/session\n/*.out\n/core*\n/props\n/socket-ssl\n/resolve\n/cookies\n/*.bb\n/*.da\n/*.bbg\n/ca*.pem\n/chain.pem\n/*.p12\n/client.*\n/clientdsa.*\n/output.pem\n/libtest.*\n/clog\n/largefile\n/xmlreq\n/sparse.bin\n/*.gc*\n/random.txt\n/nssdb*\n/makekeys\n/ca2\n/ca1\n/ca3\n/foobar.txt\n/server.key\n/hello.txt\n/enclient.*\n/clientp.*\n"
  },
  {
    "path": "test/COPYING",
    "content": "\t\t    GNU GENERAL PUBLIC LICENSE\n\t\t       Version 2, June 1991\n\n Copyright (C) 1989, 1991 Free Software Foundation, Inc.\n                          675 Mass Ave, Cambridge, MA 02139, USA\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n\t\t\t    Preamble\n\n  The licenses for most software are designed to take away your\nfreedom to share and change it.  By contrast, the GNU General Public\nLicense is intended to guarantee your freedom to share and change free\nsoftware--to make sure the software is free for all its users.  This\nGeneral Public License applies to most of the Free Software\nFoundation's software and to any other program whose authors commit to\nusing it.  (Some other Free Software Foundation software is covered by\nthe GNU Library General Public License instead.)  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthis service if you wish), that you receive source code or can get it\nif you want it, that you can change the software or use pieces of it\nin new free programs; and that you know you can do these things.\n\n  To protect your rights, we need to make restrictions that forbid\nanyone to deny you these rights or to ask you to surrender the rights.\nThese restrictions translate to certain responsibilities for you if you\ndistribute copies of the software, or if you modify it.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must give the recipients all the rights that\nyou have.  You must make sure that they, too, receive or can get the\nsource code.  And you must show them these terms so they know their\nrights.\n\n  We protect your rights with two steps: (1) copyright the software, and\n(2) offer you this license which gives you legal permission to copy,\ndistribute and/or modify the software.\n\n  Also, for each author's protection and ours, we want to make certain\nthat everyone understands that there is no warranty for this free\nsoftware.  If the software is modified by someone else and passed on, we\nwant its recipients to know that what they have is not the original, so\nthat any problems introduced by others will not reflect on the original\nauthors' reputations.\n\n  Finally, any free program is threatened constantly by software\npatents.  We wish to avoid the danger that redistributors of a free\nprogram will individually obtain patent licenses, in effect making the\nprogram proprietary.  To prevent this, we have made it clear that any\npatent must be licensed for everyone's free use or not licensed at all.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\f\n\t\t    GNU GENERAL PUBLIC LICENSE\n   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n  0. This License applies to any program or other work which contains\na notice placed by the copyright holder saying it may be distributed\nunder the terms of this General Public License.  The \"Program\", below,\nrefers to any such program or work, and a \"work based on the Program\"\nmeans either the Program or any derivative work under copyright law:\nthat is to say, a work containing the Program or a portion of it,\neither verbatim or with modifications and/or translated into another\nlanguage.  (Hereinafter, translation is included without limitation in\nthe term \"modification\".)  Each licensee is addressed as \"you\".\n\nActivities other than copying, distribution and modification are not\ncovered by this License; they are outside its scope.  The act of\nrunning the Program is not restricted, and the output from the Program\nis covered only if its contents constitute a work based on the\nProgram (independent of having been made by running the Program).\nWhether that is true depends on what the Program does.\n\n  1. You may copy and distribute verbatim copies of the Program's\nsource code as you receive it, in any medium, provided that you\nconspicuously and appropriately publish on each copy an appropriate\ncopyright notice and disclaimer of warranty; keep intact all the\nnotices that refer to this License and to the absence of any warranty;\nand give any other recipients of the Program a copy of this License\nalong with the Program.\n\nYou may charge a fee for the physical act of transferring a copy, and\nyou may at your option offer warranty protection in exchange for a fee.\n\n  2. You may modify your copy or copies of the Program or any portion\nof it, thus forming a work based on the Program, and copy and\ndistribute such modifications or work under the terms of Section 1\nabove, provided that you also meet all of these conditions:\n\n    a) You must cause the modified files to carry prominent notices\n    stating that you changed the files and the date of any change.\n\n    b) You must cause any work that you distribute or publish, that in\n    whole or in part contains or is derived from the Program or any\n    part thereof, to be licensed as a whole at no charge to all third\n    parties under the terms of this License.\n\n    c) If the modified program normally reads commands interactively\n    when run, you must cause it, when started running for such\n    interactive use in the most ordinary way, to print or display an\n    announcement including an appropriate copyright notice and a\n    notice that there is no warranty (or else, saying that you provide\n    a warranty) and that users may redistribute the program under\n    these conditions, and telling the user how to view a copy of this\n    License.  (Exception: if the Program itself is interactive but\n    does not normally print such an announcement, your work based on\n    the Program is not required to print an announcement.)\n\f\nThese requirements apply to the modified work as a whole.  If\nidentifiable sections of that work are not derived from the Program,\nand can be reasonably considered independent and separate works in\nthemselves, then this License, and its terms, do not apply to those\nsections when you distribute them as separate works.  But when you\ndistribute the same sections as part of a whole which is a work based\non the Program, the distribution of the whole must be on the terms of\nthis License, whose permissions for other licensees extend to the\nentire whole, and thus to each and every part regardless of who wrote it.\n\nThus, it is not the intent of this section to claim rights or contest\nyour rights to work written entirely by you; rather, the intent is to\nexercise the right to control the distribution of derivative or\ncollective works based on the Program.\n\nIn addition, mere aggregation of another work not based on the Program\nwith the Program (or with a work based on the Program) on a volume of\na storage or distribution medium does not bring the other work under\nthe scope of this License.\n\n  3. You may copy and distribute the Program (or a work based on it,\nunder Section 2) in object code or executable form under the terms of\nSections 1 and 2 above provided that you also do one of the following:\n\n    a) Accompany it with the complete corresponding machine-readable\n    source code, which must be distributed under the terms of Sections\n    1 and 2 above on a medium customarily used for software interchange; or,\n\n    b) Accompany it with a written offer, valid for at least three\n    years, to give any third party, for a charge no more than your\n    cost of physically performing source distribution, a complete\n    machine-readable copy of the corresponding source code, to be\n    distributed under the terms of Sections 1 and 2 above on a medium\n    customarily used for software interchange; or,\n\n    c) Accompany it with the information you received as to the offer\n    to distribute corresponding source code.  (This alternative is\n    allowed only for noncommercial distribution and only if you\n    received the program in object code or executable form with such\n    an offer, in accord with Subsection b above.)\n\nThe source code for a work means the preferred form of the work for\nmaking modifications to it.  For an executable work, complete source\ncode means all the source code for all modules it contains, plus any\nassociated interface definition files, plus the scripts used to\ncontrol compilation and installation of the executable.  However, as a\nspecial exception, the source code distributed need not include\nanything that is normally distributed (in either source or binary\nform) with the major components (compiler, kernel, and so on) of the\noperating system on which the executable runs, unless that component\nitself accompanies the executable.\n\nIf distribution of executable or object code is made by offering\naccess to copy from a designated place, then offering equivalent\naccess to copy the source code from the same place counts as\ndistribution of the source code, even though third parties are not\ncompelled to copy the source along with the object code.\n\f\n  4. You may not copy, modify, sublicense, or distribute the Program\nexcept as expressly provided under this License.  Any attempt\notherwise to copy, modify, sublicense or distribute the Program is\nvoid, and will automatically terminate your rights under this License.\nHowever, parties who have received copies, or rights, from you under\nthis License will not have their licenses terminated so long as such\nparties remain in full compliance.\n\n  5. You are not required to accept this License, since you have not\nsigned it.  However, nothing else grants you permission to modify or\ndistribute the Program or its derivative works.  These actions are\nprohibited by law if you do not accept this License.  Therefore, by\nmodifying or distributing the Program (or any work based on the\nProgram), you indicate your acceptance of this License to do so, and\nall its terms and conditions for copying, distributing or modifying\nthe Program or works based on it.\n\n  6. Each time you redistribute the Program (or any work based on the\nProgram), the recipient automatically receives a license from the\noriginal licensor to copy, distribute or modify the Program subject to\nthese terms and conditions.  You may not impose any further\nrestrictions on the recipients' exercise of the rights granted herein.\nYou are not responsible for enforcing compliance by third parties to\nthis License.\n\n  7. If, as a consequence of a court judgment or allegation of patent\ninfringement or for any other reason (not limited to patent issues),\nconditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot\ndistribute so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you\nmay not distribute the Program at all.  For example, if a patent\nlicense would not permit royalty-free redistribution of the Program by\nall those who receive copies directly or indirectly through you, then\nthe only way you could satisfy both it and this License would be to\nrefrain entirely from distribution of the Program.\n\nIf any portion of this section is held invalid or unenforceable under\nany particular circumstance, the balance of the section is intended to\napply and the section as a whole is intended to apply in other\ncircumstances.\n\nIt is not the purpose of this section to induce you to infringe any\npatents or other property right claims or to contest validity of any\nsuch claims; this section has the sole purpose of protecting the\nintegrity of the free software distribution system, which is\nimplemented by public license practices.  Many people have made\ngenerous contributions to the wide range of software distributed\nthrough that system in reliance on consistent application of that\nsystem; it is up to the author/donor to decide if he or she is willing\nto distribute software through any other system and a licensee cannot\nimpose that choice.\n\nThis section is intended to make thoroughly clear what is believed to\nbe a consequence of the rest of this License.\n\f\n  8. If the distribution and/or use of the Program is restricted in\ncertain countries either by patents or by copyrighted interfaces, the\noriginal copyright holder who places the Program under this License\nmay add an explicit geographical distribution limitation excluding\nthose countries, so that distribution is permitted only in or among\ncountries not thus excluded.  In such case, this License incorporates\nthe limitation as if written in the body of this License.\n\n  9. The Free Software Foundation may publish revised and/or new versions\nof the General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\nEach version is given a distinguishing version number.  If the Program\nspecifies a version number of this License which applies to it and \"any\nlater version\", you have the option of following the terms and conditions\neither of that version or of any later version published by the Free\nSoftware Foundation.  If the Program does not specify a version number of\nthis License, you may choose any version ever published by the Free Software\nFoundation.\n\n  10. If you wish to incorporate parts of the Program into other free\nprograms whose distribution conditions are different, write to the author\nto ask for permission.  For software which is copyrighted by the Free\nSoftware Foundation, write to the Free Software Foundation; we sometimes\nmake exceptions for this.  Our decision will be guided by the two goals\nof preserving the free status of all derivatives of our free software and\nof promoting the sharing and reuse of software generally.\n\n\t\t\t    NO WARRANTY\n\n  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\nFOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN\nOTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\nPROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\nOR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS\nTO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE\nPROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\nREPAIR OR CORRECTION.\n\n  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\nREDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\nINCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\nOUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\nTO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\nYOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\nPROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGES.\n\n\t\t     END OF TERMS AND CONDITIONS\n\f\n\tAppendix: How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nconvey the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) 19yy  <name of author>\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program; if not, write to the Free Software\n    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\nAlso add information on how to contact you by electronic and paper mail.\n\nIf the program is interactive, make it output a short notice like this\nwhen it starts in an interactive mode:\n\n    Gnomovision version 69, Copyright (C) 19yy name of author\n    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, the commands you use may\nbe called something other than `show w' and `show c'; they could even be\nmouse-clicks or menu items--whatever suits your program.\n\nYou should also get your employer (if you work as a programmer) or your\nschool, if any, to sign a \"copyright disclaimer\" for the program, if\nnecessary.  Here is a sample; alter the names:\n\n  Yoyodyne, Inc., hereby disclaims all copyright interest in the program\n  `Gnomovision' (which makes passes at compilers) written by James Hacker.\n\n  <signature of Ty Coon>, 1 April 1989\n  Ty Coon, President of Vice\n\nThis General Public License does not permit incorporating your program into\nproprietary programs.  If your program is a subroutine library, you may\nconsider it more useful to permit linking proprietary applications with the\nlibrary.  If this is what you want to do, use the GNU Library General\nPublic License instead of this License.\n"
  },
  {
    "path": "test/ChangeLog",
    "content": "Wed Aug 25 21:05:28 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* cookies.c: Removed.\n\n\t* Makefile.in: Updated.\n\nWed Aug 25 19:47:28 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* socket.c (do_connect, begin): Simplify do_connect use.\n\nWed Aug 25 18:28:19 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* xml.c (matches, fail_parse): Test for UTF-8 BOM handling.\n\nMon Jul  5 18:41:07 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* basic.c (content_type): Test for correct default charset for\n\ttext/xml content-type by RFC3280.\n\nMon Jul  5 10:59:17 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\tAdd XFAIL regression tests for trio of ne_compress.c bugs:\n\t\n\t* compress.c (reader): Validate that a size=0 call comes only\n\tafter the expected response data, and use struct string.\n\t(do_fetch): Pass a struct string to reader and adapt for failure\n\tlogic.\n\t(auth_cb, retry_compress_helper, retry_compress,\n\tretry_notcompress): New tests.\n\nSun Jul  4 21:55:00 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* utils.c (serve_sstring_slowly, serve_sstring): Moved from\n\tsockets.c, renamed from serve_string_slowly, serve_sstring.\n\n\t* sockets.c: All callers updated.\n\nSun May  2 21:16:45 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* util-tests.c (regress_dates): Add regression tests.\n\nWed Apr 14 10:45:43 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* props.c (regress, patch_regress): Add regression tests for\n\tCAN-2004-0179 issues.\n\nThu Apr  8 13:57:04 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* largefile.c (read_large_response): Go faster: turn off debugging\n\tduring request dispatch.\n\nWed Apr  7 13:39:37 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* auth.c (basic): Add some multi-scheme challenges.\n\nWed Apr  7 13:14:16 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (s_progress): Use NE_FMT_OFF_T for printing off_t's\n\tthroughout.\n\nSun Feb 22 23:38:05 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (expect_100_once, serve_100_once): Adjust for new\n\t100-continue interface.\n\t(expect_100_nobody): New test.\n\nSun Feb 22 20:39:15 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* cookies.c (parsing): Use ne_cookie_empty_cache.\n\nSun Feb 22 17:28:41 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* props.c (pfind_simple): Test for whitespace handling.\n\nSun Feb 22 16:31:52 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* auth.c (basic): Test handling of Basic challenge in presence of\n\tmultiple challenges.\n\nSun Feb 15 12:34:13 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* makekeys.sh, openssl.conf: Create new utf8subj.cert,\n\tbmpsubj.cert, t61subj.cert certificates.\n\n\t* ssl.c (dname_readable): Test that ne_ssl_readable_dname always\n\tgives back UTF-8.\n\nSat Feb 14 21:59:17 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* xml.c (fail_parse): Add tests for invalid NCNames in namespace\n\tprefix declaration and as element names.\n\nSun Jan 25 15:21:56 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* largefile.c (serve_large_response, read_large_response): New\n\ttest.\n\nSat Jan 24 18:10:14 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* Makefile.in: Fix test suite for 'make' implementatinos which\n\tdon't handle single-suffix inference rules.\n\nSat Jan  3 14:10:14 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* largefile.c (send_high_offset): Renamed from send_large_file.\n\nSat Jan  3 13:57:16 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* Makefile.in (BASIC_TESTS): Add cookies.\n\nThu Jan  1 17:42:30 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* util-tests.c (support): Check for NE_FEATURE_LFS.\n\n\t* largefile.c: New file.\n\n\t* Makefile.in: Add lfs-check, largefile, largefile.lo targets.\n\nSat Nov 15 08:04:22 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (idna_hostname, dup_header, serve_check_host): New\n\ttest.\n\nFri Nov 14 14:06:57 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* util-tests.c (support): Test for NE_FEATURE_IDNA.\n\nFri Nov 14 11:26:29 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* acl.c: Remove NEON_NODAV condition.\n\n\t* stubs.c: Use new NE_HAVE_* conditions.\n\n\t* util-tests.c (supports): Test new ne_has_support interface.\n\nThu Nov 13 20:33:44 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (no_body_205): New test.\n\nTue Nov 11 20:36:43 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\tAdjust for ne_xml_valid->ne_xml_failure API change.\n\t\n\t* xml.c (chardata, startelm_abort, endelm_abort, parse_match):\n\tCheck for propagation of negative failure codes.\n\t(fail_parse): Check for positive failure code.\n\t(attributes): Use ne_xml_failure.\n\nSat Oct 25 00:11:29 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ssl.c (fail_truncated_eof): Remove test.\n\nTue Oct 21 20:29:46 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ssl.c (fail_tunnel, proxy_tunnel): Fix non-C89 code,\n\tRadu Greab.\n\nThu Oct  9 19:42:13 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* socket.c (ssl_closure): Fix occassional spurious errors.\n\t\nTue Oct  7 20:23:35 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ssl.c (ssl_server): Handle several requests if required.\n\t(tunnel_header): New function.\n\t(serve_tunnel): Fail with a 500 if the request included\n\tan Authenticate header; take an ssl_server_args pointer\n\tas userdata.\n\t(fail_tunnel, proxy_tunnel): Adjust accordingly.\n\t(apt_post_send): Adjust for 401 check.\n\t(auth_tunnel_creds): New test.\t\n\nWed Oct  1 00:30:25 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ssl.c (simple_sslv2): Regression test.\n\t(ssl_server): Create SSL_CTX locally; optionally create an\n\tSSLv2-only server.\n\t(init_ssl): Do not create the SSL_CTX.\n\nWed Sep 17 19:57:22 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ssl.c: Refactor around single SSL server function.\n\t(ssl_server): Combination of do_ssl_response and old serve_*\n\tfunctions.  All callers updated.\n\nSun Sep 14 12:27:22 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* socket.c (write_reset, read_reset): Skip if no RESET was\n\treturned.\n\nSun Sep 14 11:01:08 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* Makefile.in: Fix building the 'resolve' tool.\n\nSat Sep  6 12:29:53 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* makekeys.sh, openssl.conf: Generate altname5.cert with an IPv4\n\taddress in the subjectAltName attribute.\n\n\t* ssl.c (ipaddr_altname): Test for IPv4 address in subjectAltName.\n\nSat Sep  6 12:28:55 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* Makefile.in: Clear the SUFFIXES list; use standard make syntax;\n\tfix build of 'basic' on some platforms.\n\nSat Aug 30 18:59:24 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* Makefile.in: Rewrite to use libtool to build object files and\n\tlibtest.\n\n\t* run.sh: Don't set LD_LIBRARY_PATH.\n\nWed Jul 23 23:25:39 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* compress.c (do_fetch): Check for response truncation\n\tfor success case.\n\t(fail_corrupt1, fail_corrupt2): New tests.\n\nSat Jun 21 12:59:49 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (versions): Fix and enable test.\n\nWed Jun 18 20:09:59 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (is_alive): Adapt for new socket API.\n\n\t* socket.c (do_connect, addr_connect): Likewise.\n\nTue May 20 20:14:03 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ssl.c (cert_fingerprint): Fix for VPATH builds.\n\nSat May 10 17:13:05 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* xml.c (matches): Add regression test for prefix matching bug\n\tfixed in 0.18.0.\n\nSat Apr 26 19:22:29 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (any_te_header): New function.\n\nWed Apr 23 18:24:19 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* stubs.c (stub_ssl): Test ne_ssl_cert_import, ne_ssl_cert_export,\n\tne_ssl_cert_write stubs.\n\nWed Apr 23 14:05:38 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ssl.c (read_write): New function.\n\nWed Apr 23 00:34:44 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ssl.c (cache_cert, verify_cache): New functions.\n\nWed Apr 23 00:14:14 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ssl.c (any_ssl_request): Free the cert after passing it to\n\tne_ssl_trust_cert.\n\nTue Apr 22 23:24:33 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* string-tests.c (unbase64): Improve coverage.\n\nTue Apr 22 20:25:15 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ssl.c (import_export, flatten_pem, cert_compare): New functions.\n\nTue Apr 22 18:32:43 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* string-tests.c (b64_check, unbase64): New functions.\n\t(base64): Use b64_check.\n\nTue Apr 22 15:54:04 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* string-tests.c (base64): Test decoding binary data which\n\tcontains bytes with the high bit set.\n\nTue Apr 22 14:18:03 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* string-tests.c (base64): Moved here...\n\n\t* util-tests.c (base64): ...from here.\n\nTue Apr 22 13:17:48 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ssl.c (just_serve_string, fail_not_ssl): New functions.\n\nTue Apr 22 13:09:13 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* stubs.c (stub_ssl): Test ne_ssl_cert_validity stub.\n\nTue Apr 22 11:35:10 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (versions): Run test as XFAIL.\n\nTue Apr 22 11:33:43 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* util-tests.c (version_string): New function.\n\nTue Apr 22 09:23:27 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ssl.c (check_validity, cert_validity): New functions.\n\nMon Apr 21 19:45:39 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* util-tests.c (digest_md5): Replace ne_md5_buffer.\n\t(md5): Use digest_md5; test 500-byte string.\n\nMon Apr 21 18:38:02 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* xml.c (fail_parse): Call ne_xml_parse with length=0 finish\n\tparse.\n\nMon Apr 21 17:18:45 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* props.c: Add tests for ne_207.h interface and ne_simple_propfind\n\tfrom ne_props.h.\n\n\t* xml.c: Add tests for new XML interface.\n\n\t* Makefile.in: Run props tests before lock since the latter is\n\timplemented using the former.\n\nMon Apr  7 22:27:18 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* stubs.c (stub_ssl): Test for ne_ssl_cert_identity stub.\n\nMon Apr  7 22:17:56 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ssl.c (cert_fingerprint): Renamed from fingerprint.\n\t(check_identity, cert_identities): New functions.\t\n\nSun Apr  6 20:18:30 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* stubs.c (stub_ssl): Adjust for new clicert API.\n\nSun Apr  6 20:12:48 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ssl.c (dname_compare): Renamed from comparisons.\n\t(dname_readable): New function.\n\n\t* makekeys.sh: Create justmail.cert.\n\nSun Apr  6 20:00:18 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ssl.c (keypw_prompt): Removed function.\n\t(init, load_client_cert, client_cert_provided): Adapt for new\n\tclicert API.\n\t(ccert_unencrypted): New function.\n\nFri Apr  4 22:34:12 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (fail_request_with_error): Refactored from\n\tfail_request; check for a particular error string.\n\t(fail_request): Use fail_request_with_error.\n\t(invalid_response_gives_error): New function.\n\t(fail_long_header): Use it.\n\t(fail_corrupt_chunks): New function.\n\nSat Mar 29 14:39:20 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ssl.c (comparisons): New function.\n\n\t* stubs.c (stub_ssl): Test ne_ssl_dname_cmp.\n\nSat Mar 29 13:58:37 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* makekeys.sh: Generate noclient.p12.\n\n\t* ssl.c (load_client_cert): Test ne_ssl_clicert_name.\n\n\t* stubs.c (stub_ssl): Check for ne_ssl_clicert_name stub.\n\nSat Mar 29 13:31:35 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ssl.c (load_client_cert): Test ne_ssl_clicert_owner.\n\nFri Mar 28 22:13:55 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ssl.c (fingerprint): New function.\n\n\t* stubs.c (stub_ssl): Check for ne_ssl_cert_digest stub.\n\nWed Mar 26 22:52:15 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ssl.c (fail_missing_CN): New function.\n\n\t* makekeys.sh: Generate missingcn.cert.\n\n\t* openssl.conf: Allow commonName to be omitted from CSR.\n\nWed Mar 26 22:41:48 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ssl.c (load_server_certs): Renamed from load_ca; test loading\n\tnon-existent file.\n\nWed Mar 26 20:38:08 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* stubs.c (stub_ssl): Updated for new SSL interface.\n\nTue Mar 25 20:32:07 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\tUpdate tests for changes to SSL interface:\n\t\n\t* socket.c (init_ssl): Use ne_ssl_context_create,\n\tne_ssl_cert_read, ne_ssl_ctx_trustcert.\n\t(begin): Use ne_sock_connect_ssl.\n\n\t* ssl.c (serve_ssl_chained, trust_default_ca, load_client_cert,\n\tcheck_dname, check_cert_dnames, check_cert, check_chain,\n\tparse_chain, cc_check_dnames, cc_provided_dnames): New functions.\n\t(serve_ccert): Always trust SERVER_CERT; optionally call\n\tSSL_CTX_set_client_CA_list.\n\t(any_ssl_request, load_ca, fail_truncated_eof): Use\n\tne_ssl_cert_read and ne_ssl_trust_cert.\n\t(keypw_prompt): Fail if userdata is NULL.\n\t(fail_load_ccerts, load_pkcs12_ccert, load_pem_ccert, check_DNs):\n\tRemoved functions.\n\t(parse_cert): Use check_cert.\n\t(client_cert_provided, client_cert_pkcs12): Rewritten for new API.\n\n\t* makekeys.sh: Generate calist.pem, unclient.p12.\n\nWed Mar 12 22:36:27 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* redirect.c (simple): Fold in tests for 30[237] redirects for\n\tbetter coverage.\n\t(no_redirect): Another test for _location returning NULL.\n\nWed Mar 12 22:29:45 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* redirect.c (process_redir): Factored out from check_redir.\n\t(no_redirect): New function.\n\nSun Mar  9 17:46:37 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* lock.c (fail_discover): New function.\n\nSat Mar  1 10:53:58 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* uri-tests.c (authinfo): Removed.\n\t(escapes): Test nothing-to-escape and invalid URI cases.\n\t(compares): Gain 100% branch coverage in ne_path_compare.\n\t(default_port): Test unknown scheme case.\n\t(parse): Test authinfo here, and some edge cases.\n\t(unparse): Fill in port if default.\t\n\nSat Mar  1 09:20:42 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* socket.c (multi_init): New function.\n\nSat Mar  1 08:04:09 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* string-tests.c (cleaner): New function.\n\nWed Feb 26 22:13:14 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (fail_eof_chunk, fail_eof_badclen): New tests.\n\nWed Feb 26 21:54:39 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* util-tests.c (support): New function.\n\t(bad_sl, accept_sl): More status-lines.\n\nTue Feb 25 21:06:18 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ssl.c (do_ssl_response): Fail if response contains\n\t\"Proxy-Authorization\" header.\n\t(apt_post_send, apt_creds, auth_proxy_tunnel): New functions.\n\nThu Nov 28 21:25:01 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (te_over_clength2): New test.\n\nSun Nov 17 18:59:04 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* socket.c (addr_make_v4, addr_make_v6, addr_compare): New\n\tfunctions.\n\nFri Oct 11 00:49:01 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* props.c (regress): Moved from regress.c:propfind_segv; add\n\tregression test for ne_props.c segfault fixed in rev 1.83.\n\n\t* regress.c: Removed.\n\t\nTue Oct  8 20:06:55 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* xml.c (matches): Add tests that entities in attribute values are\n\tdereferenced by the XML parser.\n\nFri Oct  4 17:10:19 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (no_body_bad_clength, no_body_empty_clength): New\n\ttests.\n\t(expect_no_body): Use better paths in the requests.\n\nTue Sep 24 21:27:33 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (fail_long_header, versions, hook_create_req): New\n\tfunctions.\t\n\nTue Sep 17 21:08:17 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* openssl.conf (neonca): Make 'countryName' optional in CA policy.\n\t(reqDN.CNfirst): New section.\n\n\t* makekeys.sh: Generate 'cnfirst.cert', which has commonName as\n\tfirst attribute in subject DN.\n\n\t* ssl.c (commonName_first): New function.\n\nTue Sep 10 21:11:18 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (fail_double_lookup): New function.\n\nSun Aug 25 23:16:33 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ssl.c (do_ssl_response): Add 'unclean' argument.\n\t(all callers changed).\n\t(serve_response_unclean, empty_truncated_eof, fail_truncated_eof):\n\tNew functions.\n\nSun Aug 25 19:16:00 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* socket.c (resolve_numeric): Test ne_addr_print too.\n\nSun Aug 25 13:39:37 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* resolve.c: New file.\n\nSun Aug 25 11:25:12 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (is_alive): Update for new ne_addr_* interface.\n\nSun Aug 25 08:31:16 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* socket.c (serve_truncate, ssl_truncate): New functions.\n\nSun Aug 25 08:28:17 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* socket.c (do_connect): New function; use new\n\tne_sock_connect/ne_addr interface.\n\t(begin) [SOCKET_SSL, !SOCKET_SSL]: Use do_connect.\n\t(resolve_numeric): Adjust for new ne_addr interface.\n\t(resolve_ipv6): Disable test.\n\nSat Aug 24 08:50:06 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (fail_statusline): New function.\n\nFri Aug 23 22:52:38 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ssl.c (init): FAILHARD if initialization fails.\n\nWed Aug 21 13:29:58 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* uri-tests.c (null_uri): Removed test.\n\t(parse): More tests including IPv6 address tests; use ONCMP macro.\n\t(failparse): New function.\n\t(unparse): Add URI with IPv6 address.\t\n\nWed Aug 21 13:28:37 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* socket.c (resolve_ipv6): New function.\n\nMon Aug 19 16:59:46 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* socket.c (resolve): Adapt for new ne_addr_resolve interface.\n\t(resolve_numeric): New test.\n\n\t* request.c (is_alive): Use new ne_addr_resolve interface.\n\nMon Aug 19 16:57:53 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* socket.c (begin): Fix handling of connect failure.\n\t(TO_BEGIN): Handle errors from to_begin properly.\n\nSun Aug 18 23:37:34 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* string-tests.c (str_errors): Check return value and behaviour\n\twhen error string is truncated, an\n\nSun Aug 18 23:31:51 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* util-tests.c (str_errors): Moved to...\n\n\t* string-tests.c (str_errors): here.\n\nSun Aug 18 23:11:28 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* string-tests.c (strnzcpy): New function.\n\nSun Aug 18 08:18:24 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ssl.c (caseless_match): New function.\n\n\t* makekeys.sh: Create caseless.cert.\n\nSun Aug 18 08:12:32 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ssl.c (notdns_altname): New function.\n\n\t* makekeys.sh: Create altname4.cert.\n\n\t* openssl.conf (altExt4): New section.\n\nSun Aug 18 07:42:30 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ssl.c (multi_commonName): New function.\n\t\n\t* openssl.conf (req): Use distinguished_name section as\n\tspecificied by $REQDN.\n\t(reqDN.doubleCN): New section.\n\n\t* makekeys.sh: Set $REQDN; create twocn.cert.\n\nSun Aug 18 00:47:19 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ssl.c (accept_signed_cert): New function, factored out from\n\tsimple.\n\t(simple): Use accept_signed_cert.\n\t(subject_altname, two_subject_altname, two_subject_altname2):\n\tNew function.\n\n\t* openssl.conf: Add extension sections altExt, altExt2, altExt3.\n\n\t* makekeys.sh: Generate altname.cert, altname2.cert,\n\taltname3.cert.\n\nSat Aug 17 18:41:42 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* makekeys.sh (csr_fields): New function; generate output for\n\t`openssl req'.\n\nSat Aug 17 18:27:36 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* makekeys.sh: Add CA and REQ variables to simplify OpenSSL\n\tinvocation.  Pass -config to req rather than relying on installed\n\tdefault configuration.\n\n\t* openssl.conf: Add `req' and `reqDN' sections to allow use with\n\t`openssl req' command.  Add CA basic constraint extention to\n\tcertificates used.\n\nSat Aug 10 10:42:57 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* makekeys.sh: Use openssl binary as ${OPENSSL}.\n\n\t* Makefile.in: Pick up OPENSSL from configure, and pass it through\n\tto makekeys.sh.\n\nSat Aug 10 10:18:15 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* socket.c (begin): Don't use run-time initialization.\n\n\t* request.c (s_progress): Fix warnings on FreeBSD.\n\nMon Aug  5 21:08:24 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ssl.c (ccert_provider, client_cert_provided): New functions.\n\t(fail_load_ccerts): Enable function.\n\nSun Aug  4 22:32:43 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (serve_abort, retry_after_abort): New functions.\n\nSun Aug  4 13:28:47 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (continued_header): New function.\n\nSun Aug  4 12:54:52 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* socket.c [SOCKET_SSL] (ssl_closure): New function; use instead\n\tof read_reset, write_reset for SOCKET_SSL build.\n\nSun Aug  4 12:27:34 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\tBuild socket.c twice, once for testing over SSL connections:\n\n\t* Makefile.in (socket-ssl.o, socket-ssl): New targets.\n\t(SSL_TESTS): Include socket-ssl target.\n\n\t* socket.c [SOCKET_SSL] (init_ssl, wrap_serve): New functions.\n\t[SOCKET_SSL] (begin): Alternate implementation.\n\nSat Aug  3 22:20:59 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* session.c (privates): New function.\n\nSat Aug  3 22:20:14 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* auth.c (fail_auth_cb, tunnel_regress): New function.\n\nSat Aug  3 22:12:48 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* auth.c (forget_regress): New function.\n\nSun Jul 28 12:24:02 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* lock.c (lock_timeout, submit_test, lock_shared): Use ne_concat,\n\tnot CONCAT? macros.\n\n\t* ssl.c (init, fail_expired, fail_notvalid): Likewise.\n\nThu Jul 25 00:04:47 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* string-tests.c (buf_concat, buf_concat2, buf_concat3): Renamed\n\tfrom concat, concat1, concat3).\n\t(concat): New function.\n\nSun Jul 14 11:42:03 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* util-tests.c (versioning): New function.\n\nThu Jul 11 17:24:29 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (no_headers): New function.\n\nWed Jul 10 22:58:01 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* utils.c (any_2xx_request_body): New function.\n\nWed Jul 10 22:44:12 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (ptimeout_eof, ptimeout_eof2, close_not_retried,\n\tserve_close2): New functions.\n\t(abort_respbody): Rejoin child earlier for reliable results.\n\nSun Jul  7 12:17:11 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* socket.c (expect_eof): Better error reporting.\n\t(good_close): Split from finish().\n\t(finish): Use good_close.\n\t(expect_write_closed, write_reset, read_reset): Add tests that\n\tan ECONNRESET is treated as a SOCK_CLOSED failure.\n\nSun Jul  7 08:38:12 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* utils.c (serve_response): Use discard_body().\n\nSun Jul  7 08:28:56 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* socket.c (serve_expect, full_write, small_writes, large_writes,\n\techo_server, echo_expect, echo_lines): New functions.\n\nSat Jul  6 13:11:33 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (serve_eof, fail_early_eof, fail_eof_continued,\n\tfail_eof_headers): New functions.\n\nSat Jul  6 08:58:17 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (serve_100_once, expect_100_once): New functions.\n\nFri Jul  5 21:43:58 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* auth.c (username): Use the correct spelling of Aladdin.\n\t(auth_hdr): Simplify debug messages.\n\t(auth_serve): Fail if no Authorization header is given.\n\t(basic): Check for response status.\n\nFri Jul  5 21:41:02 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* utils.c (any_2xx_request): New function.\n\nSun Jun 30 17:10:59 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (fail_noserver): Factor out from host_not_found.\n\t(fail_lookup): Equivalent to old host_not_found.\n\t(fail_connect, abort_respbody): New function.\n\nSun Jun 30 14:32:32 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (fail_chunksize): New function.\n\nSun Jun 30 10:39:17 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (test_persist): Factor out from persist; take\n\tresponse and response body as arguments.\n\t(persist_http11): New function, equivalent to old persist.\n\t(persist_chunked, persist_http10): New functions.\n\nSun Jun 30 10:25:07 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* utils.c (serve_response): Factor out from single_serve_string,\n\tmany_serve_string.\n\t(single_serve_string, many_serve_string): Use serve_response.\n\nSun Jun 30 09:13:55 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (expect_response, persist, persist_timeout,\n\tmulti_header): Rely on the fact that the test framework\n\twill reap the server.\n\t(expect_no_body, no_body_304, no_body_204, no_body_HEAD,\n\tno_body_chunks): New functions.\n\nTue Jun 25 23:05:42 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (trailing_header): New function.\n\nSun Jun 23 23:00:03 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ssl.c (no_verify): Fix sixth argument to any_ssl_request.\n\nSun Jun 23 15:21:06 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* Makefile.in (grind): New target.\n\n\t* run.sh: Respect $HARNESS.\n\nSun Jun 23 15:20:38 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* props.c: New file.\n\nSun Jun 23 09:37:10 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* makekeys.sh: Ignore failure from `hostname -[sdf]' commands, as\n\tappropriate tests are skipped on failure.\n\nSun Jun 23 08:33:50 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (host_not_found): Use any_request(); simplify.\n\t(proxy_no_resolve): New function.\n\nSun Jun 16 11:40:19 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ssl.c (do_ssl_response): Succeed if connection is closed\n\tby client after negotiation.\n\t(serve_tunnel, fail_tunnel, proxy_tunnel): New functions.\n\nMon Jun 10 21:18:03 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* redirect.c (check_redir): Await server child before returning.\n\nSun Jun  9 13:05:25 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* socket.c (DECL): Don't use run-time initialization.\n\t(single_read, single_peek, small_reads, read_and_peek, line_closure,\n\tlarger_read, line_toolong): Use DECL, as last declaration.\n\nSun Jun  9 13:03:36 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* compress.c (reader, do_fetch): Check that inflated data is of\n\texpected length.\n\nSun Jun  9 11:40:54 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* redirect.c (struct redir_args): Add 'path' field.\n\t(any_request): Use path in Request-URI.\n\t(simple, redir_303, non_absolute): Fill in path.\n\t(relative_1, relative_2): New functions.\n\nTue Jun  4 16:56:08 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* uri-tests.c (parents): Improve ne_path_parent tests.\n\nMon Jun  3 18:22:31 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* cookies.c: New file.\n\nSun Jun  2 10:06:42 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* basic.c (dav_capabilities): New function.\n\nSat Jun  1 10:39:04 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* socket.c (to_begin, to_end, peek_timeout, read_timeout,\n\treadline_timeout, fullread_timeout): New functions.\n\nSat Jun  1 10:38:13 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (read_timeout): Use sleepy_server.\n\t(hung_server): Removed.\n\nSat Jun  1 10:32:45 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* utils.c (sleepy_server): New function.\n\nThu May 30 20:00:40 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* socket.c (finish): New function, factored out from common code.\n\t(small_reads, read_and_peek, larger_read): Use it.\n\t(line_simple, line_closure, line_empty, line_toolong, line_mingle,\n\tline_chunked): New functions.\n\nSun May 26 14:54:52 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (fill_uri, match_hostport, hostports): Moved functions\n\tto session.c.\n\n\t* session.c: New file.\n\nFri May 24 08:14:21 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (match_hostport, hostports): New functions.\n\nTue May 21 21:29:25 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* redirect.c: New file.\n\nSun May 19 18:25:48 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* auth.c, lock.c, regress.c, socket.c, ssl.c, utils.c, utils.h:\n\tUpdate for socket API change; s/sock_/ne_sock_/,\n\ts/SOCK_/NE_SOCK_/.\n\nWed May  8 19:41:24 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ssl.c (do_ssl_response): Take response body as parameter; all\n\tcallers changed.\n\t(serve_eof, simple_eof): New functions.\t\n\nWed May  8 17:17:27 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* socket.c: New file.\n\n\t* sock-tests.c: Removed file.\n\n\t* Makefile.in: Updated accordingly.\n\nWed May  8 11:53:35 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (host_not_found): New function.\n\nWed May  1 21:41:02 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* uri-tests.c (parse): New function.\n\t(simple, simple_ssl): Adjust for ne_uri_parse port default.\n\nTue Apr 23 21:39:09 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (read_timeout): Better diagnostic for test failure\n\tcases.\n\nSun Apr 14 12:00:19 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* basic.c (content_type): Updated to reflect default charset\n\tISO-8859-1 for text/ media types.\n\nSun Apr  7 17:35:21 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* run.sh: Set MALLOC_CHECK_ so glibc's heap corruption detection\n\tis enabled.\n\nSun Apr  7 17:30:37 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* compress.c (do_fetch): Reset 'failed' flag to zero each time.\n\nWed Apr  3 20:16:43 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (NO_BODY): Renamed from NOBODY (all callers changed).\n\t(empty_header, ignore_header_ws, ignore_header_ws2): New tests.\n\t(ignore_header_ws3): Renamed from ignore_header_spaces.\t\n\nTue Apr  2 21:09:33 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (expect_header_value): New function.\n\t (ignore_header_case, ignore_header_spaces,\n\tignore_header_tabs): New tests.\n\nMon Mar 25 21:51:24 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* lock.c (multi_lock_response, lock_shared): New function.\n\t(lock_compare): Factored out from discover_results.\n\t(discover, lock_timeout, submit_test): Adjust for lock API\n\tchanges.\n\nMon Mar 25 21:36:55 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ssl.c (fail_ssl_request): Check failure bits against\n\tNE_SSL_FAILMASK.\n\nSun Mar 10 22:07:48 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* stubs.c (stub_decompress, sd_reader): New function.\n\nSun Mar 10 21:39:29 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* lock.c (activelock): New function, factored out from\n\tlock_response.\n\t(lock_response): Use activelock; adjust argument types.\n\t(make_lock): Adjusted for lock_response arg changes.\n\t(discard_response, serve_discovery, discover_result, discover):\n\tNew functions.\n\nWed Mar  6 22:22:04 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* lock.c (submit_test): Handle failures gracefully.\n\nWed Mar  6 21:23:27 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* lock.c (submit_test): Update to expect an absoluteURI in If:\n\theaders.\n\nWed Mar  6 21:17:37 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* uri-tests.c (unparse): New function.\n\nTue Mar  5 22:59:37 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* uri-tests.c (cmp): Checks for case-insensitive comparison, and\n\tempty path, \"/\" equivalence.\n\nMon Mar  4 01:07:03 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (blank_response): Add test for potential segfault\n\tin strip_eol (would fail if run under Electric Fence).\n\nSun Mar  3 20:50:01 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* lock.c (make_lock, store_single, store_several, got_if_header,\n\tserve_verify_if, do_request, submit_test, if_simple,\n\tif_under_infinite, if_infinite_over, if_child, if_covered_child):\n\tNew tests.\n\n\t(lock_timeout): Adjusted for API changes.\n\nSun Mar  3 15:29:05 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* uri-tests.c (cmp_differ, cmp): New functions.\n\nSun Mar  3 11:08:36 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (fill_uri): New function.\n\nSun Feb 17 21:31:21 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ssl.c (fqdn_match): Removed test.\n\nSun Feb 17 20:32:16 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* makekeys.sh: Create keypair for client cert.\n\n\t* ssl.c (do_ssl_response, any_ssl_request, all callers thereof):\n\tBetter error handling.\n\t(serve_ccert, load_pem_ccert, keypw_prompt, load_pkcs12_ccert,\n\tfail_load_ccerts, client_cert_pem, client_cert_pkcs12): New\n\tfunctions.\n\nSun Feb 17 11:54:19 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* basic.c (do_range): Factored out from\n\tget_range/fail_range_length.\n\t(get_range, fail_range_length): Use do_range.\n\t(fail_range_units, fail_range_notrange, fail_range_unsatify): New\n\ttests.\n\nSun Feb 17 11:36:00 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* basic.c (get_range, fail_range_length): New functions.\n\nSat Feb 16 23:29:40 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* xml.c: New file.\n\n\t* Makefile.in (DAV_TESTS): Add xml tests.\n\nSat Feb 16 15:26:27 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* compress.c (do_fetch): Rename from fetch(); add 'expect_fail'\n\tparamater.  (fetch): Re-implement using do_fetch.\n\t(fail_trailing, fail_bad_csum, fail_truncate): New functions.\n\n\t* Makefile.in (trailing.gz, truncated.gz, badcsum.gz): New helper\n\tfiles.\n\nThu Feb 14 19:09:42 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (everywhere): Simplify use of expect_response.\n\nThu Feb 14 19:05:48 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (ignore_bad_headers): New function.\n\nMon Feb 11 22:06:40 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* makekeys.sh: If the hostname command is clever enough to give\n\tFQDN, hostname, domainname, then create wildcard.cert; cert with a\n\twildcard commonName.\n\n\t* ssl.c (wildcard_match): New function\n\nMon Feb 11 21:55:52 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ssl.c (any_ssl_request): Take session pointer, don't\n\tinitialize here.  (DEFSESS): New macro.\n\t(everywhere): Use DEFSESS rather than passing pointer-to-\n\tsession pointer.\t\n\nMon Feb 11 20:44:44 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ssl.c (fqdn_match): Test for FQDN matching against non-qualified\n\tFQDN.\n\t(makekeys.sh): Create server cert with FQDN.\n\nSun Feb 10 12:36:55 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (chunk_oversize): New function.\n\nSat Feb  9 21:12:47 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (reason_phrase): New function.\n\nSat Feb  9 16:50:58 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (read_timeout, hung_server): New functions.\n\nThu Feb  7 22:58:31 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ssl.c (cache_verify, no_verify, count_vfy): New functions.\n\nThu Feb  7 19:39:33 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ssl.c (any_ssl_request): Take server function as argument: all\n\tcallers changed.\n\t(fail_ssl_request): Renamed from failreq; uses any_ssl_request.\n\nWed Feb  6 20:43:32 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ssl.c (load_ca): New function.\n\nWed Feb  6 20:36:15 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ssl.c (any_ssl_request): Make ca_cert and verify_fn arguments\n\toptional.\n\t(trustall): Removed function.\n\t(simple): Use the CA cert; no need for a verify function.\n\t(parse_cert): Don't give a CA cert, force use of verify function.\n\t(failreq): Bug fix, don't trust server cert as CA.\n\t(fail_wrongCN, fail_notvalid, fail_expired): Pass server cert\n\tas CA cert server cert is self-signed.\n\nTue Feb  5 20:33:42 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ssl.c (fail_untrusted_ca, fail_self_signed): New tests.\n\t(fail_serve): New function.\n\t(failreq, any_ssl_request): Take ca cert argument.\n\t(check_DNs, trustall, get_failures): Adjust for new verify\n\tcallback interface.\n\nSat Feb  2 14:18:11 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ssl.c (do_ssl_response): Factored out from serve_ssl.\n\t(serve_ssl): Use do_ssl_response.\n\t(serve_scache, session_cache): New functions.\n\nThu Jan 31 21:09:58 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* Makefile.in (ca-stamp): New target.\n\n\t* makekeys.sh: New helper script.\n\n\t* ssl.c (parse_cert, fail_wrongCN, fail_expired, fail_notvalid):\n\tNew tests.\n\t(any_ssl_request, trustall, check_DNs, failreq): New auxiliaries.\n\nThu Jan 31 20:42:38 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* wrongcn.pem, notvalid.pem, expired.pem, server.key: New files.\n\n\t* Makefile.in: Remove targets to generate certs.\n\nWed Jan 30 21:15:33 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* Makefile.in (wrongcn.pem): New target.\n\nWed Jan 30 19:58:18 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* string-tests.c: Updated for ne_buffer API change.\n\nSat Jan 26 11:23:34 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* Makefile.in: Pick up appropriate TESTS, HELPERS from configure.\n\t(ssltests*, davtests*): Remove crud.\n\n\t* compress.c: Presume zlib support present if built.\n\nSun Jan 20 23:29:37 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* ssl.c: New file.\n\n\t* Makefile.in (ssltests-no, ssltests-yes, server.pem, server.key):\n\tNew targets.\n\t(check): Conditionally run SSL tests.\n\nSun Jan 20 13:20:56 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* Makefile.in (davtests-no, davtests-yes): Separate test programs\n\twhich require DAV support; only run if DAV is enabled.\n\n\t* Makefile.in (test): Pass SRCDIR env var through to run.sh.\n\n\t* run.sh: Pass SRCDIR as argv[1] to test programs.\n\n\t* compress.c (init): New function.  Use 'newsfn' global for\n\tfilename of NEWS file.\n\nSun Jan 20 13:06:40 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* Makefile.in: Fixes for VPATH build\n\nMon Jan 14 01:58:39 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* basic.c (content_type): Add harsher charset handling tests.\n\nSun Jan 13 14:01:57 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* lock.c (lock_timeout): Use make_session. \n\n\t* acl.c (test_acl): Use make_session.\n\n\t* auth.c (basic, retries): Use make_session.\n\nSun Jan 13 14:01:13 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* utils.c (make_session): New function.\n\nSun Jan 13 14:00:34 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* basic.c (content_type): Rename ctype to ct; check if charset is\n\tunexpectedly set.\n\nSun Jan 13 13:58:07 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* basic.c: New file.\n\n\t* Makefile.in: Add `basic' test suite.\n\nMon Jan  7 22:05:33 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* Makefile.in: Don't pass CFLAGS to CC when linking.\n\nMon Jan  7 21:46:03 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* lock.c: New file.\n\n\t* Makefile.in: Add 'lock' to TESTS, build lock.\n\nMon Jan  7 21:17:21 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* skeleton.c: Add skeleton test suite.\n\nTue Jan  1 21:47:09 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* Makefile.in: Use CPPFLAGS correctly.\n\nSun Dec  9 14:02:50 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* string-tests.c (ONCMP): New macro.  (everywhere): Use it.\n\t(grow): Add ne_buffer_grow test.\n\nSun Dec  9 13:12:27 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* string-tests.c (concat2, concat3): New ne_buffer_concat tests.\n\nSat Dec  1 18:35:29 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* utils.c (any_request): Don't set the error context.\n\nSat Dec  1 12:21:48 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* auth.c (retry_failure, retry_fail_cb, retry_fail_serve): New\n\tfunctions.\n\nTue Nov 27 21:24:22 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (s_progress, provide_progress, send_progress): New\n\tfunctions.\n\nSun Nov 18 19:11:23 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* auth.c (send_response): New function.  (auth_serve): Simplify\n\tusing send_response.  (retry_serve, retry_cb, retries): New\n\tfunctions.\n\nSat Nov 17 22:32:29 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* auth.c (auth_serve, basic): Simplify, use a persistent\n\tconnection and any_request() to work with --disable-dav builds.\n\nSat Nov 17 22:30:43 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* utils.c (any_request): New function.\n\nSun Oct 28 19:38:05 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* Makefile.in: Use explicit link rules.\n\nFri Oct 26 20:08:33 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (persist_timeout): Test behaviour when connection\n\tcloses after between 1 and 10 requests.\n\nFri Oct 26 20:04:27 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* utils.c (many_serve_string): New function.\n\nSun Oct  7 17:48:53 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* utils.c: New file.\n\n\t* request.c (single_serve_string): Moved to utils.c.\n\n\t* Makefile.in: Link utils.o into all libtest.a. Move libtest.a\n\tinto this directory.\n\nSun Oct  7 15:01:47 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (persist, persist_timeout, serve_twice, is_alive): New\n\tfunctions.  (closed_connection): Avoid race condition.\n\nSat Oct  6 14:33:42 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (prepare_request, finish_request): Renamed from\n\tmake_request, destroy_request.  (skip_interim_1xx, skip_many_1xx,\n\tskip_1xx_hdrs): New functions.\n\nWed Oct  3 00:03:33 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (fail_request): Optionally include a request body, and\n\toptionally presume the server runs \"forever\".  (all callers\n\tchanged).  (serve_close, closed_connection): New function.\n\nSat Sep 29 14:08:16 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* compress.c (fetch): Update for new decompression API.\n\nSat Sep 29 11:21:56 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* compress.c: New file.\n\n\t* Makefile.in: Build compress test, and some its helpers.  Add\n\t-lneon to LIBS, and pick up NEON_CFLAGS.\n\nThu Sep 27 20:31:51 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* utils.h: New file.\n\n\t* request.c: Moved ONREQ() into utils.h\n\nMon Aug 27 00:34:56 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* regress.c: New file.\n\nMon Aug 27 00:33:13 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (discard_request): Moved into common/child.c.\n\t(make_request, destroy_request): Convenience functions.\n\t(serve_non_http, not_http): New test.\n\nSun Jun 24 22:15:46 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* test.[ch], child.[ch]: Moved into 'common' subdir.\n\n\t* Makefile.in: Updated likewise.\n\nTue Jun 19 22:00:06 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* util-tests.c (parse_dates): Test date parsers.\n\nSun Jun 10 17:36:11 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (infinite_headers, unbounded_headers): New test.\n\nSun Jun 10 16:38:53 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* child.c [HAVE_PIPE]: Use a pipe between child and parent to know\n\twhen the child is ready to accept connections.  Avoids boring\n\tsleep()ing.\n\nFri Jun  8 21:19:35 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* tests.c (segv, main): Remove SEGV handler in favour of useful\n\tcore dumps.\n\nMon Jun  4 01:15:52 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* child.c (server_socket): Set socket family correctly.\n\nThu May 31 08:58:41 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* util-tests.c (md5_alignment): New test for MD5 alignment issue\n\ton Sparc.\n\nThu May 31 00:40:43 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* child.c (minisleep): Just sleep for a second anyway.\n\nThu May 31 00:19:16 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* child.c (server_socket): Casts for bind and setsockopt arguments.\n\nThu May 31 00:02:21 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (send_bodies): Test callback-provided request bodies.\n\nWed May 30 22:37:08 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* tests.c (child_segv): New function.  (in_child): Install\n\tdifferent SEGV handler.  (segv): Sleep so the re-raised SEGV\n\tsignal gets handled and we dump core.\n\nWed May 30 19:24:32 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (send_bodies): New test for sending request bodies.\n\nWed May 16 21:19:49 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (expect_response): Renamed, fold together\n\tsingle_request and do_get_request.  (all callers changed)\n\nWed May 16 20:59:19 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (construct_get, run_request): New functions.\n\t(fold_headers, fold_many_headers, multi_header): New tests.\n\nSat May 12 17:37:36 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* server.c: Renamed from http-tests.c.\n\nSat May 12 17:35:05 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* child.c (minisleep): New function.  (spawn_server, reap_server):\n\tNew functions.  (server_child): Call in_child.\n\nSat May 12 17:33:57 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* tests.c (main): Open two log files for debugging messages.\n\t(in_child): Switch to debug using child log.\n\nSat May 12 11:18:18 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* tests.c (main): Call sock_init.  (segv): Re-raise SEGV signal\n\tafter printing message.\n\nMon May  7 10:38:50 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (chunk_syntax_1, chunk_syntax_2, chunk_syntax_3,\n\tchunk_syntax_4, chunk_syntax_5): Split down from chunk_syntax.\n\nMon May  7 10:37:38 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* util-tests.c (base64): Update for ne_base64() changes.  Add\n\ttests for binary data.\n\nSun May  6 23:55:36 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* tests.h (ON): Use global buffer 'on_err_buf'.  Make 'name'\n\tvariable public.\n\nSun May  6 23:53:06 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (single_serve_string): General version of\n\tsingle_serve_*.  (single_request): Pass in expected response body.\n\t(single_get_*): Use new single_request/single_serve_string.\n\t(chunk_syntax): Add some tests for chunk syntax.\n\nSun May  6 22:29:36 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* child.c, child.h: New files, split down from request.c.\n\nSun May  6 21:53:28 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (spawn_server): Sleep for a while to let the server\n\tget going.  (do_request): Use passed parameters when creating\n\trequest.\n\nSun May  6 21:34:27 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c (spawn_server): Use callback to handle the server side\n\tof connection.  (single_request): New function.  (single_get_eof,\n\tsingle_get_clength, single_get_chunked): New functions.\n\t(reap_server): New function.\n\nSun May  6 20:02:32 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* request.c: New file.\n\nWed May  2 12:08:53 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* string-tests.c (token1, token2, nulls, empty, quoted, badquotes,\n\tshave, combo): New tests for ne_token and ne_shave.\n\nWed May  2 12:04:52 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* string-tests.c: Updated for sbuffer -> ne_buffer changes.\n\nWed May  2 01:08:45 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* Makefile.in (check): Alias for test goal.\n\nWed May  2 01:08:36 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* tests.c (segv): Disable SEGV handler once handling it.\n\nSun Apr 29 14:57:59 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* uri-tests.c (slash): Check behaviour of passing zero-length URI.\n\nSun Apr 29 13:43:59 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* Makefile.in (clean): New target.  (libtest.a): Depend on libneon\n\tto force rebuilds when necessary.  (all): Build but don't test.\n\nSun Apr 29 13:41:13 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* util-tests.c: Add status line with leading garbage.\n\nSun Apr 29 13:39:53 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* util-tests.c (status_lines): Add some tests for invalid status\n\tlines too.\n\nSun Apr 29 13:38:31 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* tests.c (main): Use basename(argv[0]) as suite name.  Fail if no\n\ttests are in the functions vector.\n\nSun Apr 29 11:06:45 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* tests.c (segv): New function.  (main): Add SIGSEGV handler.\n\nFri Apr 27 00:00:12 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* util-tests.c (base64): New test.\n\nThu Apr 26 22:39:44 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* uri-tests.c (just_hostname, just_path, null_uri): New tests.\n\nThu Apr 26 22:03:58 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* util-tests.c (md5): Test of MD5 functions.\n\nMon Apr 23 23:08:02 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http-tests.c (simple_head): Add HEAD test.\n\nMon Apr 23 22:49:52 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* http-tests.c (simple_get): Check for EOF after reading response\n\tbody of HTTP/1.0 GET request.\n\n\t(null_resource): New function, test for 404 on null resource.\n\n\n"
  },
  {
    "path": "test/Makefile.in",
    "content": "# Makefile for neon test suite.\n\nSHELL = @SHELL@\nCPPFLAGS = @CPPFLAGS@ -I. -I$(top_srcdir)/src -I$(top_srcdir)/test/common\nCFLAGS = @CFLAGS@ @NEON_CFLAGS@\nLDFLAGS = @LDFLAGS@\nDEFS = @DEFS@\n\ntop_builddir = ..\ntop_srcdir = @top_srcdir@\nsrcdir = @srcdir@\nVPATH = @srcdir@\n\nLIBS = @LIBS@\nTEST_LIBS = $(LIBTEST) $(LIBS)\nCC = @CC@\nOPENSSL = @OPENSSL@\n\nHELPERS = @HELPERS@ foobar.txt\nBASIC_TESTS = uri-tests util-tests string-tests socket \\\n\tsession request auth basic stubs redirect\nZLIB_TESTS = compress\nZLIB_HELPERS = file1.gz file2.gz trailing.gz badcsum.gz truncated.gz \\\n\tcorrupt1.gz corrupt2.gz empty.gz random.txt hello.txt hello.gz\nDAV_TESTS = xml xmlreq twooh7 oldacl acl3744 props lock\nSSL_TESTS = socket-ssl ssl\nSSL_HELPERS = ca-stamp\nTESTS = @TESTS@\nVALGRIND = valgrind --tool=memcheck --leak-check=yes --trace-children=no --show-reachable=yes\n\n# Make every object depend on libneon.la to force a rebuild on any src/* changes\nOBJDEPS = $(srcdir)/common/tests.h $(srcdir)/common/child.h $(srcdir)/utils.h \\\n\t$(top_builddir)/config.h $(top_builddir)/src/libneon.la\n# Test program just depends on libtest\nDEPS = $(LIBTEST)\nLDADD = $(DEPS) $(LIBS)\n\nLIBTEST = libtest.la\nLIBNEON = $(top_builddir)/src/libneon.la\n\nLIBTOOL = @LIBTOOL@ --silent\nTEST_LDFLAGS = @TEST_LDFLAGS@\nLINK = $(LIBTOOL) --mode=link $(CC) $(LDFLAGS) $(TEST_LDFLAGS)\nCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(CPPFLAGS) $(CFLAGS)\n\nprefix = @prefix@\nexec_prefix = @exec_prefix@\nlibdir = @libdir@\n\nINSTALL_PROGRAM = @INSTALL_PROGRAM@\nINSTALL_DATA = @INSTALL_DATA@\nINSTALL_SCRIPT = @INSTALL_SCRIPT@\nINSTALL = @INSTALL@\nTEST_INSTALL_DIR = $(libdir)/neon-tests\n\nINSTALL_HELPERS = $(HELPERS) server.key makekeys \\\n\t$(srcdir)/openssl.conf $(srcdir)/notvalid.pem \\\n\t$(srcdir)/expired.pem\n\n.SUFFIXES:\n.SUFFIXES: .lo .c\n\n# By default, compile but don't run the tests.\nall: $(TESTS)\n\nclean:\n\trm -f $(TESTS) $(HELPERS) *.o *.lo common/*.o common/*.lo libtest.*a *.log\n\trm -f *.gc* *.da *.bb* common/*.bb* common/*.gc* common/*.da\n\trm -rf ca ca2 .libs nssdb*\n\trm -f ca-stamp client.key *.csr ssigned.pem wrongcn.pem \\\n\t   server.cert client.cert *.p12 *.cert sparse.bin\n\ncheck: $(TESTS) $(HELPERS)\n\t@SRCDIR=$(srcdir) $(SHELL) $(srcdir)/run.sh $(TESTS)\n\ngrind: $(TESTS) $(HELPERS)\n\t@SRCDIR=$(srcdir) HARNESS=\"$(VALGRIND)\" $(SHELL) $(srcdir)/run.sh $(TESTS)\n\nlfs-check: largefile $(LFS_HELPERS)\n\t@SRCDIR=$(srcdir) $(SHELL) $(srcdir)/run.sh largefile\n\ninstall: $(TESTS) $(HELPERS)\n\t@$(INSTALL) -d $(DESTDIR)$(TEST_INSTALL_DIR)\n\t@$(INSTALL) -d $(DESTDIR)$(TEST_INSTALL_DIR)/bin\n\t@$(INSTALL) -d $(DESTDIR)$(TEST_INSTALL_DIR)/data\n\t@for t in $(TESTS); do \\\n\t $(LIBTOOL) --mode=install \\\n\t      $(INSTALL_PROGRAM) $$t $(DESTDIR)$(TEST_INSTALL_DIR)/bin; \\\n\tdone\n\t@for h in $(INSTALL_HELPERS); do \\\n\t $(INSTALL_DATA) $$h $(DESTDIR)$(TEST_INSTALL_DIR)/data; \\\n\tdone\n\t@$(INSTALL_PROGRAM) -p $(srcdir)/run-tests.sh $(DESTDIR)$(TEST_INSTALL_DIR)\n\nNEWS = $(top_srcdir)/NEWS\n\nfile1.gz: $(NEWS)\n\tgzip -c --no-name $(NEWS) > $@\n\nfile2.gz: $(NEWS)\n\tgzip -c --name $(NEWS) > $@\n\nhello.txt:\n\techo hello world > $@\n\nhello.gz: hello.txt\n\tgzip -c hello.txt > $@\n\n# gzip file with trailing bytes.\ntrailing.gz: $(NEWS)\n\tgzip -c --no-name $(NEWS) > $@\n\techo \"hello, world\" >> $@\n\ntruncated.gz: file1.gz\n\tdd if=file1.gz of=$@ bs=2048 count=2\n\nbadcsum.gz: file1.gz\n\tdd of=$@ if=file1.gz bs=1 count=`perl -e 'printf \"%d\", (stat(\"file1.gz\"))[7] - 8;'`\n\techo 'broken!' >> $@\n\ncorrupt1.gz: file1.gz\n\tdd of=$@ if=file1.gz bs=1 count=500\n\tcat $(NEWS) >> $@\n\ncorrupt2.gz: $(NEWS)\n\tcat $(NEWS) > $@\n\nempty.gz:\n\ttouch $@\n\nrandom.txt: $(NEWS)\n\tcat $(NEWS) > $@\n\nfoobar.txt:\n\techo foobar > $@\n\n# Dummy target to create the CA keys etc.  makekeys stderr is redirected\n# since it changes for every invocation; not helpful for regression\n# testing.\nca-stamp: makekeys $(srcdir)/openssl.conf\n\trm -rf ca ca2\n\tOPENSSL=$(OPENSSL) \\\n\t $(SHELL) makekeys $(srcdir) 2>makekeys.out\n\t@echo timestamp > ca-stamp\n\nMakefile: $(srcdir)/Makefile.in\n\tcd .. && ./config.status test/Makefile\n\nmakekeys: $(srcdir)/makekeys.sh\n\tcd .. && ./config.status test/makekeys\n\nLIBOBJS = common/tests.lo common/child.lo utils.lo util-socks.lo\n\n$(LIBTEST): $(LIBOBJS)\n\t$(LINK) -o $(LIBTEST) $(LIBOBJS) $(LIBNEON) $(LIBS)\n\n.c.lo:\n\t$(COMPILE) -c $< -o $@\n\n# Recompile socket.c with SOCKET_SSL defined\nsocket-ssl.lo: $(srcdir)/socket.c $(HDRS)\n\t$(COMPILE) -DSOCKET_SSL -c $(srcdir)/socket.c -o $@\n\nsocket-ssl: socket-ssl.lo $(LIBTEST)\n\t$(LINK) -o $@ socket-ssl.lo $(TEST_LIBS)\n\nresolve: resolve.lo $(LIBNEON)\n\t$(LINK) -o $@ resolve.lo $(LIBNEON)\n\ncommon/tests.lo: $(srcdir)/common/tests.c $(OBJDEPS)\ncommon/child.lo: $(srcdir)/common/child.c $(OBJDEPS) \nutils.lo: $(srcdir)/utils.c $(OBJDEPS)\nutil-socks.lo: $(srcdir)/util-socks.c $(OBJDEPS)\nauth.lo: $(srcdir)/auth.c $(OBJDEPS)\nuri-tests.lo: $(srcdir)/uri-tests.c $(OBJDEPS)\nutil-tests.lo: $(srcdir)/util-tests.c $(OBJDEPS)\nstring-tests.lo: $(srcdir)/string-tests.c $(OBJDEPS)\nsocket.lo: $(srcdir)/socket.c $(OBJDEPS)\nserver.lo: $(srcdir)/server.c $(OBJDEPS)\nrequest.lo: $(srcdir)/request.c $(OBJDEPS)\nregress.lo: $(srcdir)/regress.c $(OBJDEPS)\ncompress.lo: $(srcdir)/compress.c $(OBJDEPS)\noldacl.lo: $(srcdir)/oldacl.c $(OBJDEPS)\nacl3744.lo: $(srcdir)/acl3744.c $(OBJDEPS)\nutils.lo: $(srcdir)/utils.c $(OBJDEPS)\nstubs.lo: $(srcdir)/stubs.c $(OBJDEPS)\nprops.lo: $(srcdir)/props.c $(OBJDEPS)\nsession.lo: $(srcdir)/session.c $(OBJDEPS)\nredirect.lo: $(srcdir)/redirect.c $(OBJDEPS)\nbasic.lo: $(srcdir)/basic.c $(OBJDEPS)\nssl.lo: $(srcdir)/ssl.c $(OBJDEPS)\nlock.lo: $(srcdir)/lock.c $(OBJDEPS)\nlargefile.lo: $(srcdir)/largefile.c $(OBJDEPS)\n\nauth: auth.lo $(DEPS)\n\t$(LINK) -o $@ auth.lo $(LDADD)\nbasic: basic.lo $(DEPS)\n\t$(LINK) -o $@ basic.lo $(LDADD)\nuri-tests: uri-tests.lo $(DEPS)\n\t$(LINK) -o $@ uri-tests.lo $(LDADD)\nutil-tests: util-tests.lo $(DEPS)\n\t$(LINK) -o $@ util-tests.lo $(LDADD)\nstring-tests: string-tests.lo $(DEPS)\n\t$(LINK) -o $@ string-tests.lo $(LDADD)\nsocket: socket.lo $(DEPS)\n\t$(LINK) -o $@ socket.lo $(LDADD)\nserver: server.lo $(DEPS)\n\t$(LINK) -o $@ server.lo $(LDADD)\nrequest: request.lo $(DEPS)\n\t$(LINK) -o $@ request.lo $(LDADD)\nregress: regress.lo $(DEPS)\n\t$(LINK) -o $@ regress.lo $(LDADD)\ncompress: compress.lo $(DEPS)\n\t$(LINK) -o $@ compress.lo $(LDADD)\noldacl: oldacl.lo $(DEPS)\n\t$(LINK) -o $@ oldacl.lo $(LDADD)\nacl3744: acl3744.lo $(DEPS)\n\t$(LINK) -o $@ acl3744.lo $(LDADD)\nutils: utils.lo $(DEPS)\n\t$(LINK) -o $@ utils.lo $(LDADD)\nstubs: stubs.lo $(DEPS)\n\t$(LINK) -o $@ stubs.lo $(LDADD)\nprops: props.lo $(DEPS)\n\t$(LINK) -o $@ props.lo $(LDADD)\nsession: session.lo $(DEPS)\n\t$(LINK) -o $@ session.lo $(LDADD)\nredirect: redirect.lo $(DEPS)\n\t$(LINK) -o $@ redirect.lo $(LDADD)\nssl: ssl.lo $(DEPS)\n\t$(LINK) -o $@ ssl.lo $(LDADD)\nxml: xml.lo $(DEPS)\n\t$(LINK) -o $@ xml.lo $(LDADD)\nxmlreq: xmlreq.lo $(DEPS)\n\t$(LINK) -o $@ xmlreq.lo $(LDADD)\ntwooh7: twooh7.lo $(DEPS)\n\t$(LINK) -o $@ twooh7.lo $(LDADD)\nlock: lock.lo $(DEPS)\n\t$(LINK) -o $@ lock.lo $(LDADD)\nlargefile: largefile.lo $(DEPS)\n\t$(LINK) -o $@ largefile.lo $(LDADD)\n"
  },
  {
    "path": "test/README",
    "content": "\nStupidly Simple Test Suite for neon\n-----------------------------------\n\nThe aim of the test suite is two-fold:\n\n 1. ensure compliance to the relevant RFCs in network behaviour.\n\n 2. ensure that the promises made by the public API are met \n by the current implementation.\n\nThe file `STATUS' makes an attempt at listing RFC requirements and how\nthe test suite tests whether neon meets them or not (it's not finished\nyet).\n\nThe test suite is licensed under the GPL.\n\nImportant Note About Test Failures\n----------------------------------\n\nNote that a test failure either means a bug in the test or a bug in\nthe code itself.  On platforms without pipe(), there is a race\ncondition in the code which forks a server process: if you get random\nfailures on a slow or loaded box, increase the sleep time in\ncommon/child.c:minisleep().\n\nExtra Stuff\n-----------\n\nserver-tests requires that you have a running HTTP server on localhost\nport 80, and you have copied htdocs/* to server-htdocs-root/test/*\n\nCredits\n-------\n\nThis test suite is inspired by the Subversion project, discussion on\nthe subversion mailing list, and seeing chromatic's talks on XP.  The\npresentation is inspired by the standard Perl test suite.  Imitation\nis the greatest form of flattery, right?\n"
  },
  {
    "path": "test/STATUS",
    "content": "                                                        -*- text -*-\n\nThis document attempts to list RFC requirements and determine whether\nneon meets them, or where they do not apply, etc.\n\n Yes: test written, succeeds\n No:  test written, but currently fails\n ???: no test written\n ---: feature not supported\n App: this is an application issue not a neon issue\n\n  RFC2616\n  =======\n\n3.1: MUST treat major/minor as separate digits\t\t\tYes\n3.1: MUST ignore leading zeros\t\t\t\t\tYes\n3.1: MUST only send HTTP/1.1 when appropriate\t\t\t???\n\n3.2.2: MUST use abs_path of \"/\" in Request-URI\t\t\tApp\n3.2.3: comparisons of host names MUST be case-insensitive\tYes\n       comparisons of scheme names MUST be ...\t\t\tYes\n       comparison of empty abs_path equivalent to \"/\"\t\tNo/---\n\n3.3.1: MUST accept three date formats\t\t\t\tApp/Yes [2]\n       MUST only generate RFC1123-style dates\t\t\tApp\n\n3.3.1: MUST use GMT for http-dates\t\t\t\t???\n       MUST assume GMT when parsing asctime dates\t\t???\n\n3.4.1: MUST respect charset label provided\t\t\tYes/App\n\n3.5*: content codings\t\t\t\t\t\tApp\n\n3.6: MUST requirements for multiple transfer-codings\t\t--- [4]\n\n3.6.1: parsing of chunked transfer coding\t\t\tYes\n       MUST be able to handle \"chunked\" transfer-coding\t\tYes\n       MUST ignore unknown chunk-extension extensions\t\tYes\n\n3.7: parsing of Content-Type headers\t\t\t\tYes\n\n3.7: MUST NOT have LWS between type/subtype in C-T hdr\t\tApp\n     SHOULD only send parameters to \"new HTTP apps\" (>1.0?)     App\n\n3.7.1: MUST represent HTTP message in canonical form\t\tApp\n       MUST accept CRLF/CR/LF as line-breaks in text/* media\tApp\n       MUST NOT use only CR or LF in HTTP control structures\t???\n       MUST specify charset if not ISO-8859-1\t\t\tApp\n\n3.7.2: multipart types\t\t\t\t\t\t---\n\n3.8: SHOULD have short product token\t\t\t\tYes/App [5]\n     SHOULD use product-version for version identifier\t\tYes/App\n     only product-version differs between versions\t\tYes/App\n\n3.9: Content Negotiation\t\t\t\t\t---/App\n\n3.10: Language Tags\t\t\t\t\t\t---/App\n\n3.11: Entity Tags\t\t\t\t\t\t---/App\n\n\n\n\n\n[2]: date parser is provided which handles all three formats, but no \nhandling of the Date header is present within neon.\n\n[3]: not sure if neon should be handling of this internally.\n\n[4]: neon only supports using just chunked Transfer-Coding or none.\n\n[5]: these reflect that applications may add their own product tokens\n     alongside neon's.\n"
  },
  {
    "path": "test/acl3744.c",
    "content": "/* \n   Dummy ACL tests\n   Copyright (C) 2001-2007, Joe Orton <joe@manyfish.co.uk>\n\n   This program is free software; you can redistribute it and/or modify\n   it under the terms of the GNU General Public License as published by\n   the Free Software Foundation; either version 2 of the License, or\n   (at your option) any later version.\n  \n   This program is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU General Public License for more details.\n  \n   You should have received a copy of the GNU General Public License\n   along with this program; if not, write to the Free Software\n   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\n*/\n\n#include \"ne_acl3744.h\"\n\n#include \"tests.h\"\n#include \"child.h\"\n#include \"utils.h\"\n\n/**** DUMMY TESTS: just makes sure the stuff doesn't dump core. */\n\nstatic int test_acl(const char *uri, ne_acl_entry *es, int nume)\n{\n    ne_session *sess;\n\n    CALL(make_session(&sess, single_serve_string, \n\t\t      \"HTTP/1.1 200 OK\\r\\n\"\n\t\t      \"Connection: close\\r\\n\\r\\n\"));\n    \n    ON(ne_acl3744_set(sess, uri, es, nume));\n    \n    return destroy_and_wait(sess);\n}\n\nstatic int grant_all(void)\n{\n    ne_acl_entry e = {0};\n\n    e.target = ne_acl_all;\n    e.type = ne_acl_grant;\n    e.privileges = NE_ACL_ALL;\n\n    CALL(test_acl(\"/foo\", &e, 1));\n\n    return OK;\n}\n\nstatic int deny_all(void)\n{\n    ne_acl_entry e = {0};\n\n    e.target = ne_acl_all;\n    e.type = ne_acl_deny;\n    e.privileges = NE_ACL_ALL;\n\n    CALL(test_acl(\"/foo\", &e, 1));\n\n    return OK;\n}\n\nstatic int deny_one(void)\n{\n    ne_acl_entry e = {0};\n\n    e.target = ne_acl_href;\n    e.tname = \"http://webdav.org/users/joe\";\n    e.type = ne_acl_deny;\n    e.privileges = NE_ACL_ALL;\n\n    CALL(test_acl(\"/foo\", &e, 1));\n\n    return OK;\n}       \n\nstatic int deny_byprop(void)\n{\n    ne_acl_entry e = {0};\n\n    e.target = ne_acl_property;\n    e.type = ne_acl_deny;\n    e.tname = \"owner\";\n    e.privileges = NE_ACL_ALL;\n\n    CALL(test_acl(\"/foo\", &e, 1));\n\n    return OK;\n}\n\nne_test tests[] = {\n    T(grant_all),\n    T(deny_all),\n    T(deny_one),\n    T(deny_byprop),\n    T(NULL)\n};\n"
  },
  {
    "path": "test/auth.c",
    "content": "/* \n   Authentication tests\n   Copyright (C) 2001-2009, Joe Orton <joe@manyfish.co.uk>\n\n   This program is free software; you can redistribute it and/or modify\n   it under the terms of the GNU General Public License as published by\n   the Free Software Foundation; either version 2 of the License, or\n   (at your option) any later version.\n  \n   This program is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU General Public License for more details.\n  \n   You should have received a copy of the GNU General Public License\n   along with this program; if not, write to the Free Software\n   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\n*/\n\n#include \"config.h\"\n\n#include <sys/types.h>\n\n#ifdef HAVE_STDLIB_H\n#include <stdlib.h>\n#endif\n#ifdef HAVE_UNISTD_H\n#include <unistd.h>\n#endif\n#ifdef HAVE_ARPA_INET_H\n#include <arpa/inet.h>\n#endif\n#ifdef HAVE_SYS_ENDIAN_H\n#include <sys/endian.h>\n#endif\n#ifdef HAVE_ENDIAN_H\n#include <endian.h>\n#endif\n\n#if defined(NE_HAVE_NTLM) && (defined(HAVE_SYS_ENDIAN_H) || defined(HAVE_ENDIAN_H))\n#define TEST_NTLM\n#include <ntlm.h>\n#endif\n\n#include \"ne_string.h\"\n#include \"ne_request.h\"\n#include \"ne_auth.h\"\n#include \"ne_basic.h\"\n\n#include \"tests.h\"\n#include \"child.h\"\n#include \"utils.h\"\n\nstatic const char username[] = \"Aladdin\", password[] = \"open sesame\";\nstatic const char *alt_username, *alt_username_star;\n\nstatic int auth_failed;\n\nstatic int has_sha256 = 0, has_sha512_256 = 0;\n\n#define BASIC_WALLY \"Basic realm=WallyWorld\"\n#define CHAL_WALLY \"WWW-Authenticate: \" BASIC_WALLY\n\n#define EOL \"\\r\\n\"\n\nstatic int auth_cb(void *userdata, const char *realm, int tries, \n\t\t   char *un, char *pw)\n{\n    if (strcmp(realm, \"WallyWorld\")) {\n        NE_DEBUG(NE_DBG_HTTP, \"Got wrong realm '%s'!\\n\", realm);\n        return -1;\n    }    \n    strcpy(un, userdata ? userdata : username);\n    strcpy(pw, password);\n    return tries;\n}\t\t   \n\nstatic int auth_provide_cb(void *userdata, int attempt,\n                           unsigned protocol, const char *realm,\n                           char *un, char *pw, size_t buflen)\n{\n    if (strcmp(realm, \"WallyWorld\")) {\n        NE_DEBUG(NE_DBG_HTTP, \"Got wrong realm '%s'!\\n\", realm);\n        return -1;\n    }\n    strcpy(un, alt_username);\n    strcpy(pw, password);\n    return attempt;\n}\n\nstatic void auth_hdr(char *value)\n{\n#define B \"Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==\"\n    auth_failed = strcmp(value, B);\n    NE_DEBUG(NE_DBG_HTTP, \"Got auth header: [%s]\\nWanted header:   [%s]\\n\"\n\t     \"Result: %d\\n\", value, B, auth_failed);\n#undef B\n}\n\n/* Sends a response with given response-code. If hdr is not NULL,\n * sends that header string too (appending an EOL).  If eoc is\n * non-zero, request must be last sent down a connection; otherwise,\n * clength 0 is sent to maintain a persistent connection. */\nstatic int send_response(ne_socket *sock, const char *hdr, int code, int eoc)\n{\n    char buffer[BUFSIZ];\n    \n    sprintf(buffer, \"HTTP/1.1 %d Blah Blah\" EOL, code);\n    \n    if (hdr) {\n\tstrcat(buffer, hdr);\n\tstrcat(buffer, EOL);\n    }\n\n    if (eoc) {\n\tstrcat(buffer, \"Connection: close\" EOL EOL);\n    } else {\n\tstrcat(buffer, \"Content-Length: 0\" EOL EOL);\n    }\n\t\n    return SEND_STRING(sock, buffer);\n}\n\n/* Server function which sends two responses: first requires auth,\n * second doesn't. */\nstatic int auth_serve(ne_socket *sock, void *userdata)\n{\n    char *hdr = userdata;\n\n    auth_failed = 1;\n\n    /* Register globals for discard_request. */\n    got_header = auth_hdr;\n    want_header = \"Authorization\";\n\n    discard_request(sock);\n    send_response(sock, hdr, 401, 0);\n\n    discard_request(sock);\n    send_response(sock, NULL, auth_failed?500:200, 1);\n\n    return 0;\n}\n\nstatic int init(void)\n{\n    char *p;\n\n    p = ne_strhash(NE_HASH_SHA256, \"\", NULL);\n    has_sha256 = p != NULL;\n    if (p) ne_free(p);\n\n    p = ne_strhash(NE_HASH_SHA512_256, \"\", NULL);\n    has_sha512_256 = p != NULL;\n    if (p) ne_free(p);\n\n    return lookup_localhost();\n}\n\n/* Test that various Basic auth challenges are correctly handled. */\nstatic int basic(void)\n{\n    const char *hdrs[] = {\n        /* simplest case */\n        CHAL_WALLY,\n\n        /* several challenges, one header */\n        \"WWW-Authenticate: BarFooScheme, \" BASIC_WALLY,\n\n        /* several challenges, one header */\n        CHAL_WALLY \", BarFooScheme realm=\\\"PenguinWorld\\\"\",\n\n        /* whitespace tests. */\n        \"WWW-Authenticate:   Basic realm=WallyWorld   \",\n\n        /* nego test. */\n        \"WWW-Authenticate: Negotiate fish, Basic realm=WallyWorld\",\n\n        /* nego test. */\n        \"WWW-Authenticate: Negotiate fish, bar=boo, Basic realm=WallyWorld\",\n\n        /* nego test. */\n        \"WWW-Authenticate: Negotiate, Basic realm=WallyWorld\",\n\n        /* multi-header case 1 */\n        \"WWW-Authenticate: BarFooScheme\\r\\n\"\n        CHAL_WALLY,\n        \n        /* multi-header cases 1 */\n        CHAL_WALLY \"\\r\\n\"\n        \"WWW-Authenticate: BarFooScheme bar=\\\"foo\\\"\",\n\n        /* multi-header case 3 */\n        \"WWW-Authenticate: FooBarChall foo=\\\"bar\\\"\\r\\n\"\n        CHAL_WALLY \"\\r\\n\"\n        \"WWW-Authenticate: BarFooScheme bar=\\\"foo\\\"\",\n\n        /* quoting test; fails to handle scheme properly with <= 0.28.2. */\n        \"WWW-Authenticate: Basic realm=\\\"WallyWorld\\\" , BarFooScheme\"\n    };\n    size_t n;\n    \n    for (n = 0; n < sizeof(hdrs)/sizeof(hdrs[0]); n++) {\n        ne_session *sess;\n        \n        CALL(make_session(&sess, auth_serve, (void *)hdrs[n]));\n        ne_set_server_auth(sess, auth_cb, NULL);\n        \n        CALL(any_2xx_request(sess, \"/norman\"));\n        \n        ne_session_destroy(sess);\n        CALL(await_server());\n    }\n\n    return OK;\n}\n\nstatic int retry_serve(ne_socket *sock, void *ud)\n{\n    discard_request(sock);\n    send_response(sock, CHAL_WALLY, 401, 0);\n\n    discard_request(sock);\n    send_response(sock, CHAL_WALLY, 401, 0);\n\n    discard_request(sock);\n    send_response(sock, NULL, 200, 0);\n    \n    discard_request(sock);\n    send_response(sock, CHAL_WALLY, 401, 0);\n\n    discard_request(sock);\n    send_response(sock, NULL, 200, 0);\n\n    discard_request(sock);\n    send_response(sock, NULL, 200, 0);\n\n    discard_request(sock);\n    send_response(sock, NULL, 200, 0);\n\n    discard_request(sock);\n    send_response(sock, CHAL_WALLY, 401, 0);\n\n    discard_request(sock);\n    send_response(sock, NULL, 200, 0);\n\n    discard_request(sock);\n    send_response(sock, CHAL_WALLY, 401, 0);\n\n    discard_request(sock);\n    send_response(sock, CHAL_WALLY, 401, 0);\n\n    discard_request(sock);\n    send_response(sock, CHAL_WALLY, 401, 0);\n\n    discard_request(sock);\n    send_response(sock, NULL, 200, 0);\n    \n    return OK;\n}\n\nstatic int retry_cb(void *userdata, const char *realm, int tries, \n\t\t    char *un, char *pw)\n{\n    int *count = userdata;\n\n    /* dummy creds; server ignores them anyway. */\n    strcpy(un, \"a\");\n    strcpy(pw, \"b\");\n\n    switch (*count) {\n    case 0:\n    case 1:\n\tif (tries == *count) {\n\t    *count += 1;\n\t    return 0;\n\t} else {\n\t    t_context(\"On request #%d, got attempt #%d\", *count, tries);\n\t    *count = -1;\n\t    return 1;\n\t}\n\tbreak;\n    case 2:\n    case 3:\n\t/* server fails a subsequent request, check that tries has\n\t * reset to zero. */\n\tif (tries == 0) {\n\t    *count += 1;\n\t    return 0;\n\t} else {\n\t    t_context(\"On retry after failure #%d, tries was %d\", \n\t\t      *count, tries);\n\t    *count = -1;\n\t    return 1;\n\t}\n\tbreak;\n    case 4:\n    case 5:\n\tif (tries > 1) {\n\t    t_context(\"Attempt counter reached #%d\", tries);\n\t    *count = -1;\n\t    return 1;\n\t}\n\treturn tries;\n    default:\n\tt_context(\"Count reached %d!?\", *count);\n\t*count = -1;\n    }\n    return 1;\n}\n\n/* Test that auth retries are working correctly. */\nstatic int retries(void)\n{\n    ne_session *sess;\n    int count = 0;\n    \n    CALL(make_session(&sess, retry_serve, NULL));\n\n    ne_set_server_auth(sess, retry_cb, &count);\n\n    /* This request will be 401'ed twice, then succeed. */\n    ONREQ(any_request(sess, \"/foo\"));\n\n    /* auth_cb will have set up context. */\n    CALL(count != 2);\n\n    /* this request will be 401'ed once, then succeed. */\n    ONREQ(any_request(sess, \"/foo\"));\n\n    /* auth_cb will have set up context. */\n    CALL(count != 3);\n\n    /* some 20x requests. */\n    ONREQ(any_request(sess, \"/foo\"));\n    ONREQ(any_request(sess, \"/foo\"));\n\n    /* this request will be 401'ed once, then succeed. */\n    ONREQ(any_request(sess, \"/foo\"));\n\n    /* auth_cb will have set up context. */\n    CALL(count != 4);\n\n    /* First request is 401'ed by the server at both attempts. */\n    ONV(any_request(sess, \"/foo\") != NE_AUTH,\n\t(\"auth succeeded, should have failed: %s\", ne_get_error(sess)));\n\n    count++;\n\n    /* Second request is 401'ed first time, then will succeed if\n     * retried.  0.18.0 didn't reset the attempt counter though so \n     * this didn't work. */\n    ONV(any_request(sess, \"/foo\") == NE_AUTH,\n\t(\"auth failed on second try, should have succeeded: %s\", ne_get_error(sess)));\n\n    return destroy_and_wait(sess);\n}\n\n/* crashes with neon <0.22 */\nstatic int forget_regress(void)\n{\n    ne_session *sess = ne_session_create(\"http\", \"localhost\", 1234);\n    ne_forget_auth(sess);\n    ne_session_destroy(sess);\n    return OK;    \n}\n\nstatic int fail_auth_cb(void *ud, const char *realm, int attempt, \n\t\t\tchar *un, char *pw)\n{\n    return 1;\n}\n\n/* this may trigger a segfault in neon 0.21.x and earlier. */\nstatic int tunnel_regress(void)\n{\n    ne_session *sess;\n    \n    CALL(proxied_session_server(&sess, \"http\", \"localhost\", 443,\n                                single_serve_string,\n                                \"HTTP/1.1 401 Auth failed.\\r\\n\"\n                                \"WWW-Authenticate: Basic realm=asda\\r\\n\"\n                                \"Content-Length: 0\\r\\n\\r\\n\"));\n    ne_set_server_auth(sess, fail_auth_cb, NULL);\n    any_request(sess, \"/foo\");\n\n    return destroy_and_wait(sess);\n}\n\n/* regression test for parsing a Negotiate challenge with on parameter\n * token. */\nstatic int negotiate_regress(void)\n{\n    ne_session *sess;\n    \n    CALL(session_server(&sess, single_serve_string,\n                        \"HTTP/1.1 401 Auth failed.\\r\\n\"\n                        \"WWW-Authenticate: Negotiate\\r\\n\"\n                        \"Content-Length: 0\\r\\n\\r\\n\"));\n    ne_set_server_auth(sess, fail_auth_cb, NULL);\n    any_request(sess, \"/foo\");\n\n    return destroy_and_wait(sess);\n}\n\nstatic char *digest_hdr = NULL;\n\nstatic void dup_header(char *header)\n{\n    if (digest_hdr) ne_free(digest_hdr);\n    digest_hdr = ne_strdup(header);\n}\n\n#define PARM_PROXY       (0x0001)\n#define PARM_NEXTNONCE   (0x0002)\n#define PARM_ALG         (0x0004) /* use algorithm= */\n#define PARM_AINFO       (0x0008)\n#define PARM_USERHASH    (0x0010) /* userhash=true */\n#define PARM_UHFALSE     (0x0020) /* userhash=false */\n#define PARM_ALTUSER     (0x0040)\n#define PARM_LEGACY      (0x0080)\n#define PARM_LEGACY_ONLY (0x0100)\n#define PARM_QOP         (0x0200) /* use qop= */\n#define PARM_RFC2617     (PARM_QOP|PARM_ALG) /* use algorithm= and qop= */\n#define PARM_OPTSTAR     (0x0400) /* use OPTIONS * */\n#define PARM_PARSEQOP    (0x0800) /* use qop-value parsing test */\n#define PARM_TRAILER     (0x1000) /* use chunked trailers for Auth-Info */\n\nstruct digest_parms {\n    const char *realm, *nonce, *opaque, *domain;\n    enum { ALG_MD5 = 0, ALG_MD5_SESS, ALG_SHA256, ALG_SHA256_SESS, ALG_SHA512_256, ALG_SHA512_256_SESS } alg;\n    unsigned int flags;\n    int num_requests;\n    int stale;\n    enum digest_failure {\n        fail_not,\n        fail_bogus_alg,\n        fail_req0_stale,\n        fail_req0_2069_stale,\n        fail_omit_qop,\n        fail_omit_realm,\n        fail_omit_nonce,\n        fail_ai_bad_nc,\n        fail_ai_bad_nc_syntax,\n        fail_ai_bad_digest,\n        fail_ai_bad_cnonce,\n        fail_ai_omit_cnonce,\n        fail_ai_omit_digest,\n        fail_ai_omit_nc,\n        fail_outside_domain,\n        fail_2069_weak\n    } failure;\n};\n\nstruct digest_state {\n    const char *realm, *nonce, *uri, *username, *username_star, *password, *algorithm, *qop,\n        *method, *opaque;\n    char userhash[64];\n    char *cnonce, *digest, *ncval;\n    long nc;\n    int count;\n    int uhash_bool;\n};\n\nstatic char *hash(struct digest_parms *p, ...)\n    ne_attribute_sentinel;\n\nstatic char *hash(struct digest_parms *p, ...)\n{\n    va_list ap;\n    unsigned int flags;\n    char *h;\n\n    switch (p->alg) {\n    case ALG_SHA512_256_SESS:\n    case ALG_SHA512_256:\n        flags = NE_HASH_SHA512_256;\n        break;\n    case ALG_SHA256_SESS:\n    case ALG_SHA256:\n        flags = NE_HASH_SHA256;\n        break;\n    default:\n        flags = NE_HASH_MD5;\n        break;\n    }\n\n    va_start(ap, p);\n    h = ne_vstrhash(flags, ap);\n    va_end(ap);\n\n    if (h == NULL) abort();\n\n    return h;\n}\n\n/* Write the request-digest into 'digest' (or response-digest if\n * auth_info is non-zero) for given digest auth state and\n * parameters.  */\nstatic char *make_digest(struct digest_state *state, struct digest_parms *parms,\n                         int auth_info)\n{\n    char *h_a1, *h_a2, *rv;\n\n    h_a1 = hash(parms, state->username, \":\", state->realm, \":\", \n                state->password, NULL);\n\n    if (parms->alg == ALG_MD5_SESS || parms->alg == ALG_SHA256_SESS || parms->alg == ALG_SHA512_256_SESS) {\n        char *sess_h_a1;\n\n        sess_h_a1 = hash(parms, h_a1, \":\", state->nonce, \":\", state->cnonce, NULL);\n        ne_free(h_a1);\n        h_a1 = sess_h_a1;\n    }\n\n    NE_DEBUG(NE_DBG_HTTP, \"H(A2) from %s:%s\\n\",\n             !auth_info ? state->method : \"\", state->uri);\n    h_a2 = hash(parms, !auth_info ? state->method : \"\", \":\", state->uri, NULL);\n\n    if (parms->flags & PARM_QOP) {\n        rv = hash(parms,\n                  h_a1, \":\", state->nonce, \":\",\n                  state->ncval, \":\", state->cnonce, \":\", state->qop, \":\",\n                  h_a2, NULL);\n    }\n    else {\n        /* RFC2069-style */\n        rv = hash(parms, h_a1, \":\", state->nonce, \":\", h_a2, NULL);\n    }\n\n    ne_free(h_a2);\n    ne_free(h_a1);\n\n    return rv;\n}\n\n/* Verify that the response-digest matches expected state. */\nstatic int check_digest(struct digest_state *state, struct digest_parms *parms)\n{\n    char *digest;\n\n    digest = make_digest(state, parms, 0);\n    ONV(digest == NULL,\n        (\"failed to create digest for %s\", state->algorithm));\n\n    ONV(strcmp(digest, state->digest),\n        (\"bad digest; expected %s got %s\", state->digest, digest));\n\n    ne_free(digest);\n\n    return OK;\n}\n\n#define DIGCMP(field)                                   \\\n    do {                                                \\\n        ONCMP(state->field, newstate.field,            \\\n              \"Digest response header\", #field);        \\\n    } while (0)\n\n#define NPARAM(field, param)                                    \\\n    do {                                                        \\\n        if (ne_strcasecmp(name, param) == 0) {                  \\\n            ONV(newstate.field != NULL,                         \\\n                (\"received multiple %s params: %s, %s\", param,  \\\n                 newstate.field, val));                         \\\n            newstate.field = val;                               \\\n        }                                                       \\\n    } while (0)\n#define PARAM(field) NPARAM(field, #field)\n\n/* Verify that Digest auth request header, 'header', meets expected\n * state and parameters. */\nstatic int verify_digest_header(struct digest_state *state, \n                                struct digest_parms *parms,\n                                char *header)\n{\n    char *ptr;\n    struct digest_state newstate = {0};\n\n    ptr = ne_token(&header, ' ');\n\n    ONCMP(\"Digest\", ptr, \"Digest response\", \"scheme name\");\n\n    while (header) {\n        char *name, *val;\n\n        ptr = ne_qtoken(&header, ',', \"\\\"\\'\");\n        ONN(\"quoting broken\", ptr == NULL);\n\n        name = ne_shave(ptr, \" \");\n\n        val = strchr(name, '=');\n        ONV(val == NULL, (\"bad name/value pair: %s\", name));\n        \n        *val++ = '\\0';\n\n        val = ne_shave(val, \"\\\"\\' \");\n\n        NE_DEBUG(NE_DBG_HTTP, \"got field: [%s] = [%s]\\n\", name, val);\n\n        PARAM(uri);\n        PARAM(realm);\n        PARAM(username);\n        PARAM(nonce);\n        PARAM(algorithm);\n        PARAM(qop);\n        PARAM(opaque);\n        PARAM(cnonce);\n        NPARAM(username_star, \"username*\");\n\n        if (ne_strcasecmp(name, \"nc\") == 0) {\n            long nc = strtol(val, NULL, 16);\n            \n            ONV(nc != state->nc, \n                (\"got bad nonce count: %ld (%s) not %ld\", \n                 nc, val, state->nc));\n\n            state->ncval = ne_strdup(val);\n        }\n        else if (ne_strcasecmp(name, \"response\") == 0) {\n            state->digest = ne_strdup(val);\n        }\n        else if (ne_strcasecmp(name, \"userhash\") == 0 ) {\n            newstate.uhash_bool = strcmp(val, \"true\") == 0;\n        }\n    }\n\n    ONN(\"cnonce param missing or short for 2617-style auth\",\n        (parms->flags & PARM_QOP)\n        && (newstate.cnonce == NULL\n            || strlen(newstate.cnonce) < 32));\n\n    if (alt_username_star) {\n        ONN(\"unexpected userhash=true sent\", newstate.uhash_bool);\n        ONN(\"username* missing\", newstate.username_star == NULL);\n        ONCMP(alt_username_star, newstate.username_star, \"Digest field\", \"username*\");\n    }\n    else if (parms->flags & PARM_USERHASH) {\n        ONN(\"userhash missing\", !newstate.uhash_bool);\n\n        ONCMP(state->userhash, newstate.username,\n              \"Digest username (userhash) field\", \"userhash\");\n    }\n    else {\n        ONN(\"unexpected userhash=true sent\", newstate.uhash_bool);\n        DIGCMP(username);\n    }\n\n    DIGCMP(realm);\n    if (!parms->domain)\n        DIGCMP(uri);\n    DIGCMP(nonce);\n    DIGCMP(opaque);\n    DIGCMP(algorithm);\n\n    if (parms->flags & PARM_QOP) {\n        DIGCMP(qop);\n    }\n        \n    if (newstate.cnonce) {\n        state->cnonce = ne_strdup(newstate.cnonce);\n    }\n    if (parms->domain) {\n        state->uri = ne_strdup(newstate.uri);\n    }\n\n    ONN(\"no digest param given\", !state->digest);\n\n    CALL(check_digest(state, parms));\n\n    state->nc++;\n    \n    return OK;\n}\n\nstatic char *make_authinfo_header(struct digest_state *state,\n                                  struct digest_parms *parms)\n{\n    ne_buffer *buf = ne_buffer_create();\n    char *digest, *ncval, *cnonce;\n\n    if (parms->failure == fail_ai_bad_digest) {\n        digest = ne_strdup(\"fish\");\n    } else {\n        digest = make_digest(state, parms, 1);\n    }\n\n    if (parms->failure == fail_ai_bad_nc_syntax) {\n        ncval = \"zztop\";\n    } else if (parms->failure == fail_ai_bad_nc) {\n        ncval = \"999\";\n    } else {\n        ncval = state->ncval;\n    }\n\n    if (parms->failure == fail_ai_bad_cnonce) {\n        cnonce = \"another-fish\";\n    } else {\n        cnonce = state->cnonce;\n    }\n\n    if ((parms->flags & PARM_PROXY)) {\n        ne_buffer_czappend(buf, \"Proxy-\");\n    }\n\n    ne_buffer_czappend(buf, \"Authentication-Info: \");\n\n    if ((parms->flags & PARM_QOP) == 0) {\n        ne_buffer_concat(buf, \"rspauth=\\\"\", digest, \"\\\"\", NULL);\n    }\n    else {\n        if (parms->failure != fail_ai_omit_nc) {\n            ne_buffer_concat(buf, \"nc=\", ncval, \", \", NULL);\n        }\n        if (parms->failure != fail_ai_omit_cnonce) {\n            ne_buffer_concat(buf, \"cnonce=\\\"\", cnonce, \"\\\", \", NULL);\n        } \n        if (parms->failure != fail_ai_omit_digest) {\n            ne_buffer_concat(buf, \"rspauth=\\\"\", digest, \"\\\", \", NULL);\n        }\n        if (parms->flags & PARM_NEXTNONCE) {\n            state->nonce = ne_concat(\"next-\", state->nonce, NULL);\n            ne_buffer_concat(buf, \"nextnonce=\\\"\", state->nonce, \"\\\", \", NULL);\n            state->nc = 1;\n        }\n        ne_buffer_czappend(buf, \"qop=\\\"auth\\\"\");\n    }\n\n    ne_free(digest);\n    \n    return ne_buffer_finish(buf);\n}\n\nstatic char *make_digest_header(struct digest_state *state,\n                                struct digest_parms *parms)\n{\n    ne_buffer *buf = ne_buffer_create();\n    const char *algorithm;\n\n    algorithm = parms->failure == fail_bogus_alg ? \"fish\" \n        : state->algorithm;\n\n    ne_buffer_concat(buf, \n                     (parms->flags & PARM_PROXY) ? \"Proxy-Authenticate\"\n                     : \"WWW-Authenticate\",\n                     \": Digest \"\n                     \"realm=\\\"\", parms->realm, \"\\\", \", NULL);\n    \n    if (parms->flags & PARM_ALG) {\n        ne_buffer_concat(buf, \"algorithm=\\\"\", algorithm, \"\\\", \", NULL);\n    }\n\n    if (parms->flags & PARM_PARSEQOP) {\n        ne_buffer_czappend(buf, \"qop=\\\"auth-int,fish, auth\\\", \");\n    }\n    else if (parms->flags & PARM_QOP) {\n        ne_buffer_concat(buf, \"qop=\\\"\", state->qop, \"\\\", \", NULL);\n    }\n\n    if (parms->opaque) {\n        ne_buffer_concat(buf, \"opaque=\\\"\", parms->opaque, \"\\\", \", NULL);\n    }\n\n    if (parms->domain) {\n        ne_buffer_concat(buf, \"domain=\\\"\", parms->domain, \"\\\", \", NULL);\n    }\n\n    if (parms->flags & PARM_USERHASH) {\n        ne_buffer_czappend(buf, \"userhash=true, \");\n    }\n    else if (parms->flags & PARM_UHFALSE) {\n        ne_buffer_czappend(buf, \"userhash=false, \");\n    }\n\n    if (parms->failure == fail_req0_stale\n        || parms->failure == fail_req0_2069_stale\n        || parms->stale == parms->num_requests) {\n        ne_buffer_concat(buf, \"stale='true', \", NULL);\n    }\n\n    ne_buffer_concat(buf, \"nonce=\\\"\", state->nonce, \"\\\"\", NULL);\n\n    return ne_buffer_finish(buf);\n}\n\n/* Server process for Digest auth handling. */\nstatic int serve_digest(ne_socket *sock, void *userdata)\n{\n    struct digest_parms *parms = userdata;\n    struct digest_state state;\n    char resp[NE_BUFSIZ], *rspdigest;\n\n    state.method = \"GET\";\n    \n    if ((parms->flags & PARM_PROXY))\n        state.uri = \"http://www.example.com/fish\";\n    else if (parms->domain)\n        state.uri = \"/fish/0\";\n    else if ((parms->flags & PARM_OPTSTAR)) {\n        state.method = \"OPTIONS\";\n        state.uri = \"*\";\n    }\n    else\n        state.uri = \"/fish\";\n\n    state.realm = parms->realm;\n    if (parms->nonce)\n        state.nonce = parms->nonce;\n    else {\n        unsigned char nonce[24];\n\n        ONN(\"nonce generation failed\", ne_mknonce(nonce, sizeof nonce, 0));\n\n        state.nonce = ne_base64(nonce, sizeof nonce);\n    }\n    NE_DEBUG(NE_DBG_HTTP, \"digest: nonce is %s\\n\", state.nonce);\n    state.opaque = parms->opaque;\n    if (parms->flags & PARM_ALTUSER)\n        state.username = alt_username;\n    else\n        state.username = username;\n    state.password = password;\n    state.nc = 1;\n    switch (parms->alg) {\n    case ALG_SHA512_256: state.algorithm = \"SHA-512-256\"; break;\n    case ALG_SHA512_256_SESS: state.algorithm = \"SHA-512-256-sess\"; break;\n    case ALG_SHA256: state.algorithm = \"SHA-256\"; break;\n    case ALG_SHA256_SESS: state.algorithm = \"SHA-256-sess\"; break;\n    case ALG_MD5_SESS: state.algorithm = \"MD5-sess\"; break;\n    default:\n    case ALG_MD5: state.algorithm = \"MD5\"; break;\n    }\n    state.qop = \"auth\";\n\n    if (parms->flags & PARM_USERHASH) {\n        char *uh = hash(parms, username, \":\", parms->realm, NULL);\n\n        ONN(\"userhash too long\", strlen(uh) >= sizeof state.userhash);\n\n        ne_strnzcpy(state.userhash, uh, sizeof state.userhash);\n        ne_free(uh);\n    }\n\n    state.cnonce = state.digest = state.ncval = NULL;\n\n    parms->num_requests += parms->stale ? 1 : 0;\n\n    NE_DEBUG(NE_DBG_HTTP, \">>>> Response sequence begins, %d requests.\\n\",\n             parms->num_requests);\n\n    want_header = (parms->flags & PARM_PROXY) ? \"Proxy-Authorization\" : \"Authorization\";\n    digest_hdr = NULL;\n    got_header = dup_header;\n\n    CALL(discard_request(sock));\n\n    ONV(digest_hdr != NULL,\n        (\"got unwarranted WWW-Auth header: %s\", digest_hdr));\n\n    rspdigest = make_digest_header(&state, parms);\n    ne_snprintf(resp, sizeof resp,\n                \"HTTP/1.1 %d Auth Denied\\r\\n\"\n                \"%s\\r\\n\"\n                \"Content-Length: 0\\r\\n\" \"\\r\\n\",\n                (parms->flags & PARM_PROXY) ? 407 : 401,\n                rspdigest);\n    ne_free(rspdigest);\n\n    SEND_STRING(sock, resp);\n\n    /* Give up now if we've sent a challenge which should force the\n     * client to fail immediately: */\n    if (parms->failure == fail_bogus_alg\n        || parms->failure == fail_req0_stale\n        || parms->failure == fail_req0_2069_stale) {\n        return OK;\n    }\n\n    do {\n        digest_hdr = NULL;\n        CALL(discard_request(sock));\n\n        if (digest_hdr && parms->domain && (parms->num_requests & 1) != 0) {\n            SEND_STRING(sock, \"HTTP/1.1 400 Used Auth Outside Domain\\r\\n\\r\\n\");\n            return OK;\n        }\n        else if (digest_hdr == NULL && parms->domain && (parms->num_requests & 1) != 0) {\n            /* Do nothing. */\n            NE_DEBUG(NE_DBG_HTTP, \"No Authorization header sent, good.\\n\");\n        }\n        else {\n            ONN(\"no Authorization header sent\", digest_hdr == NULL);\n\n            ONERR(sock, verify_digest_header(&state, parms, digest_hdr));\n        }\n\n        if (parms->num_requests == parms->stale) {\n            char *dig;\n            state.nonce = ne_concat(\"stale-\", state.nonce, NULL);\n            state.nc = 1;\n\n            dig = make_digest_header(&state, parms);\n            ne_snprintf(resp, sizeof resp,\n                        \"HTTP/1.1 %d Auth Denied\\r\\n\"\n                        \"%s\\r\\n\"\n                        \"Content-Length: 0\\r\\n\" \"\\r\\n\",\n                        (parms->flags & PARM_PROXY) ? 407 : 401,\n                        dig);\n            ne_free(dig);\n        }\n        else if (parms->flags & PARM_AINFO) {\n            char *ai = make_authinfo_header(&state, parms);\n\n            if (parms->flags & PARM_TRAILER) {\n                ne_snprintf(resp, sizeof resp,\n                            \"HTTP/1.1 200 Well, if you insist\\r\\n\"\n                            \"Transfer-Encoding: chunked\\r\\n\"\n                            \"\\r\\n\"\n                            \"0\\r\\n%s\\r\\n\"\n                            \"\\r\\n\", ai);\n            }\n            else {\n                ne_snprintf(resp, sizeof resp,\n                            \"HTTP/1.1 200 Well, if you insist\\r\\n\"\n                            \"Content-Length: 0\\r\\n\"\n                            \"%s\\r\\n\"\n                            \"\\r\\n\", ai);\n            }\n            \n            ne_free(ai);\n        } else {\n            ne_snprintf(resp, sizeof resp,\n                        \"HTTP/1.1 200 You did good\\r\\n\"\n                        \"Content-Length: 0\\r\\n\" \"\\r\\n\");\n        }\n\n        SEND_STRING(sock, resp);\n\n        NE_DEBUG(NE_DBG_HTTP, \"Handled request; %d requests remain.\\n\",\n                 parms->num_requests - 1);\n    } while (--parms->num_requests);\n\n    return OK;\n}\n\nstatic int test_digest(struct digest_parms *parms)\n{\n    ne_session *sess;\n    unsigned proto = NE_AUTH_DIGEST;\n\n    if ((parms->flags & PARM_LEGACY))\n        proto |= NE_AUTH_LEGACY_DIGEST;\n    else if ((parms->flags & PARM_LEGACY_ONLY))\n        proto = NE_AUTH_LEGACY_DIGEST;\n\n    NE_DEBUG(NE_DBG_HTTP, \">>>> Request sequence begins \"\n             \"(reqs=%d, nonce=%s, rfc=%s, stale=%d, proxy=%d).\\n\",\n             parms->num_requests,\n             parms->nonce, (parms->flags & PARM_QOP) ? \"2617\" : \"2069\",\n             parms->stale, !!(parms->flags & PARM_PROXY));\n\n    if ((parms->flags & PARM_PROXY)) {\n        CALL(proxied_session_server(&sess, \"http\", \"www.example.com\", 80,\n                                    serve_digest, parms));\n        ne_set_proxy_auth(sess, auth_cb, NULL);\n    } \n    else {\n        CALL(session_server(&sess, serve_digest, parms));\n        if ((parms->flags & PARM_ALTUSER))\n            ne_add_auth(sess, proto, auth_provide_cb, NULL);\n        else\n            ne_add_server_auth(sess, proto, auth_cb, NULL);\n    }\n\n    do {\n        if (parms->flags & PARM_OPTSTAR)\n            CALL(any_2xx_request_method(sess, \"OPTIONS\", \"*\"));\n        else\n            CALL(any_2xx_request(sess, \"/fish\"));\n    } while (--parms->num_requests);\n    \n    return destroy_and_wait(sess);\n}\n\n/* Test for RFC2617-style Digest auth. */\nstatic int digest(void)\n{\n    struct digest_parms parms[] = {\n        /* RFC 2617-style */\n        { \"WallyWorld\", \"this-is-a-nonce\", NULL, NULL, ALG_MD5, PARM_RFC2617, 1, 0, fail_not },\n        /* Leaving algorithm= optional. */\n        { \"WallyWorld\", \"this-is-a-nonce\", NULL, NULL, ALG_MD5, PARM_QOP, 1, 0, fail_not },\n        { \"WallyWorld\", \"this-is-also-a-nonce\", \"opaque-string\", NULL, ALG_MD5, PARM_RFC2617, 1, 0, fail_not },\n        /* ... with A-I */\n        { \"WallyWorld\", \"nonce-nonce-nonce\", \"opaque-string\", NULL, ALG_MD5, PARM_RFC2617 | PARM_AINFO, 1, 0, fail_not },\n        /* ... with md5-sess. */\n        { \"WallyWorld\", \"nonce-nonce-nonce\", \"opaque-string\", NULL, ALG_MD5_SESS, PARM_RFC2617 | PARM_AINFO, 1, 0, fail_not },\n        /* many requests, with changing nonces; tests for next-nonce handling bug. */\n        { \"WallyWorld\", \"this-is-a-nonce\", \"opaque-thingy\", NULL, ALG_MD5, PARM_RFC2617 | PARM_AINFO | PARM_NEXTNONCE, 20, 0, fail_not },\n        /* ... with qop parsing tests. */\n        { \"WallyWorld\", \"qop-parsing-test\", NULL, NULL, ALG_MD5, PARM_RFC2617 | PARM_PARSEQOP, 1, 0, fail_not },\n        /* next-nonce, use chunked trailers. */\n        { \"WallyWorld\", \"chunked-trailer\", NULL, NULL, ALG_MD5, PARM_RFC2617|PARM_AINFO|PARM_TRAILER|PARM_NEXTNONCE, 20, 0, fail_not },\n\n        /* staleness. */\n        { \"WallyWorld\", \"this-is-a-nonce\", \"opaque-thingy\", NULL, ALG_MD5, PARM_RFC2617 | PARM_AINFO, 3, 2, fail_not },\n        /* 2069 + stale */\n        { \"WallyWorld\", \"this-is-a-nonce\", NULL, NULL, ALG_MD5, PARM_LEGACY|PARM_AINFO, 3, 2, fail_not },\n\n        /* RFC 7616-style */\n        { \"WallyWorld\", \"new-day-new-nonce\", \"new-opaque\", NULL, ALG_MD5, PARM_RFC2617 | PARM_USERHASH, 1, 0, fail_not },\n        /* ... userhash=false */\n        { \"WallyWorld\", \"just-another-nonce\", \"new-opaque\", NULL, ALG_MD5, PARM_RFC2617 | PARM_UHFALSE, 1, 0, fail_not },\n\n        /* RFC 2069-style */ \n        { \"WallyWorld\", \"lah-di-da-di-dah\", NULL, NULL, ALG_MD5, PARM_LEGACY, 1, 0, fail_not },\n        { \"WallyWorld\", \"lah-lah-lah-lah\", NULL, NULL, ALG_MD5, PARM_LEGACY_ONLY, 1, 0, fail_not },\n        { \"WallyWorld\", \"fee-fi-fo-fum\", \"opaque-string\", NULL, ALG_MD5, PARM_LEGACY, 1, 0, fail_not },\n        { \"WallyWorld\", \"fee-fi-fo-fum\", \"opaque-string\", NULL, ALG_MD5, PARM_AINFO|PARM_LEGACY, 1, 0, fail_not },\n\n        /* Proxy auth */\n        { \"WallyWorld\", \"this-is-also-a-nonce\", \"opaque-string\", NULL, ALG_MD5, PARM_RFC2617|PARM_PROXY, 1, 0, fail_not },\n        /* Proxy + nextnonce */\n        { \"WallyWorld\", \"this-is-also-a-nonce\", \"opaque-string\", NULL, ALG_MD5, PARM_RFC2617|PARM_AINFO|PARM_PROXY, 1, 0, fail_not },\n\n        /* OPTIONS * test */\n        { \"WallyWorld\", \"options-nonce\", \"new-opaque\", NULL, ALG_MD5, PARM_RFC2617|PARM_USERHASH|PARM_OPTSTAR, 1, 0, fail_not },\n\n        { NULL }\n    };\n    size_t n;\n\n    for (n = 0; parms[n].realm; n++) {\n        CALL(test_digest(&parms[n]));\n\n    }\n\n    return OK;\n}\n\nstatic int digest_sha256(void)\n{\n    struct digest_parms parms[] = {\n        { \"WallyWorld\", \"nonce-sha-nonce\", \"opaque-string\", NULL, ALG_SHA256, PARM_RFC2617, 1, 0, fail_not },\n        { \"WallyWorld\", \"nonce-sha-nonce\", \"opaque-string\", NULL, ALG_SHA256, PARM_RFC2617|PARM_AINFO, 1, 0, fail_not },\n        { \"WallyWorld\", \"nonce-sha-session\", \"opaque-string\", NULL, ALG_SHA256_SESS, PARM_RFC2617|PARM_AINFO, 1, 0, fail_not },\n        { \"WallyWorld\", \"nonce-sha-nonce\", \"opaque-string\", NULL, ALG_SHA256, PARM_RFC2617|PARM_AINFO, 8, 0, fail_not },\n        \n        { NULL },\n    };\n    size_t n;\n\n    if (!has_sha256) {\n        t_context(\"SHA-256 not supported\");\n        return SKIP;\n    }\n\n    for (n = 0; parms[n].realm; n++) {\n        CALL(test_digest(&parms[n]));\n\n    }\n\n    return OK;\n}\n\nstatic int digest_sha512_256(void)\n{\n    struct digest_parms parms[] = {\n        { \"WallyWorld\", \"nonce-sha5-nonce\", \"opaque-string\", NULL, ALG_SHA512_256, PARM_RFC2617, 1, 0, fail_not },\n        { \"WallyWorld\", \"nonce-sha5-nonce\", \"opaque-string\", NULL, ALG_SHA512_256, PARM_RFC2617|PARM_AINFO, 1, 0, fail_not },\n        { \"WallyWorld\", \"nonce-sha5-session\", \"opaque-string\", NULL, ALG_SHA512_256_SESS, PARM_RFC2617|PARM_AINFO, 1, 0, fail_not },\n        { \"WallyWorld\", \"nonce-sha-nonce\", \"opaque-string\", NULL, ALG_SHA512_256_SESS, PARM_RFC2617|PARM_AINFO, 20, 0, fail_not },\n        { NULL },\n    };\n    size_t n;\n\n    if (!has_sha512_256) {\n        t_context(\"SHA-512/256 not supported\");\n        return SKIP;\n    }\n\n    for (n = 0; parms[n].realm; n++) {\n        CALL(test_digest(&parms[n]));\n\n    }\n\n    return OK;\n}\n\nstatic int digest_username_star(void)\n{\n    static const struct {\n        const char *username_raw, *username_star;\n    } ts[] = {\n        { \"Aladdin\", NULL },\n        { \"aladdin@cave.example.com\", NULL },\n        { \"foo bar\", NULL },\n        { \"Ałâddín\", \"UTF-8''A%c5%82%c3%a2dd%c3%adn\" },\n        { \"Jäsøn Doe\", \"UTF-8''J%c3%a4s%c3%b8n%20Doe\" },\n        { \"foo\\\"bar\", \"UTF-8''foo%22bar\" },\n        { NULL, NULL }\n    };\n    unsigned n;\n    int ret = OK;\n\n    for (n = 0; ret == OK && ts[n].username_raw; n++) {\n        struct digest_parms parms = {\n            \"WallyWorld\", \"nonce-sha5-nonce\", \"opaque-string\",\n            NULL, ALG_MD5, PARM_RFC2617|PARM_UHFALSE|PARM_ALTUSER, 1, 0, fail_not };\n\n        alt_username = ts[n].username_raw;\n        alt_username_star = ts[n].username_star;\n\n        ret = test_digest(&parms);\n    }\n\n    alt_username = NULL;\n    alt_username_star = NULL;\n\n    return ret;\n}\n\n\nstatic int digest_failures(void)\n{\n    struct digest_parms parms;\n    static const struct {\n        enum digest_failure mode;\n        const char *message;\n    } fails[] = {\n        { fail_ai_bad_nc, \"nonce count mismatch\" },\n        { fail_ai_bad_nc_syntax, \"could not parse nonce count\" },\n        { fail_ai_bad_digest, \"digest mismatch\" },\n        { fail_ai_bad_cnonce, \"client nonce mismatch\" },\n        { fail_ai_omit_nc, \"missing parameters\" },\n        { fail_ai_omit_digest, \"missing parameters\" },\n        { fail_ai_omit_cnonce, \"missing parameters\" },\n        { fail_bogus_alg, \"unknown algorithm\" },\n        { fail_req0_stale, \"initial Digest challenge was stale\" },\n        { fail_req0_2069_stale, \"initial Digest challenge was stale\" },\n        { fail_2069_weak, \"legacy Digest challenge not supported\" },\n        { fail_not, NULL }\n    };\n    unsigned n;\n\n    memset(&parms, 0, sizeof parms);\n    \n    parms.realm = \"WallyWorld\";\n    parms.opaque = NULL;\n    parms.num_requests = 1;\n\n    for (n = 0; fails[n].message; n++) {\n        ne_session *sess;\n        int ret;\n        unsigned protocol = NE_AUTH_DIGEST;\n\n        parms.failure = fails[n].mode;\n        parms.flags = PARM_AINFO;\n\n        if (parms.failure == fail_req0_2069_stale) protocol |= NE_AUTH_LEGACY_DIGEST;\n\n        if (parms.failure == fail_req0_2069_stale || parms.failure == fail_2069_weak)\n            parms.flags &= ~PARM_RFC2617;\n        else\n            parms.flags |= PARM_RFC2617;\n\n        NE_DEBUG(NE_DBG_HTTP, \">>> New Digest failure test %u, \"\n                 \"expecting failure '%s', protocol %x\\n\", n,\n                 fails[n].message, protocol);\n        \n        CALL(session_server(&sess, serve_digest, &parms));\n\n        ne_add_server_auth(sess, protocol, auth_cb, NULL);\n        \n        ret = any_2xx_request(sess, \"/fish\");\n        ONV(ret == NE_OK,\n            (\"request success (iter %u); expecting error '%s'\",\n             n, fails[n].message));\n\n        ONV(strstr(ne_get_error(sess), fails[n].message) == NULL,\n            (\"request fails with error '%s'; expecting '%s'\",\n             ne_get_error(sess), fails[n].message));\n\n        ne_session_destroy(sess);\n        \n        if (fails[n].mode == fail_bogus_alg\n            || fails[n].mode == fail_req0_stale\n            || fails[n].mode == fail_2069_weak) {\n            reap_server();\n        } else {\n            CALL(await_server());\n        }\n    }\n\n    return OK;\n}\n\nstatic int fail_cb(void *userdata, const char *realm, int tries, \n\t\t   char *un, char *pw)\n{\n    ne_buffer *buf = userdata;\n    char str[64];\n\n    if (strcmp(realm, \"colonic\") == 0 && ne_buffer_size(buf) == 0) {\n        ne_strnzcpy(un, \"user:name\", NE_ABUFSIZ);\n        ne_strnzcpy(pw, \"passwerd\", NE_ABUFSIZ);\n        return 0;\n    }\n\n    ne_snprintf(str, sizeof str, \"<%s, %d>\", realm, tries);\n    ne_buffer_zappend(buf, str);\n\n    return -1;\n}\n\nstatic int fail_challenge(void)\n{\n    static const struct {\n        const char *resp, *error, *challs;\n    } ts[] = {\n        /* only possible Basic parse failure. */\n        { \"Basic\", \"missing realm in Basic challenge\" },\n\n        { \"Basic realm=\\\"colonic\\\"\", \"username containing colon\" },\n\n        /* Digest parameter invalid/omitted failure cases: */\n        { \"Digest algorithm=MD5, qop=auth, nonce=\\\"foo\\\"\",\n          \"missing parameter in Digest challenge\" },\n        { \"Digest algorithm=MD5, qop=auth, realm=\\\"foo\\\"\",\n          \"missing parameter in Digest challenge\" },\n        { \"Digest algorithm=ZEBEDEE-GOES-BOING, qop=auth, realm=\\\"foo\\\"\",\n          \"unknown algorithm in Digest challenge\" },\n        { \"Digest algorithm=MD5-sess, realm=\\\"foo\\\"\",\n          \"incompatible algorithm in Digest challenge\" },\n        { \"Digest algorithm=MD5, qop=auth, nonce=\\\"foo\\\", realm=\\\"foo\\\", \"\n          \"domain=\\\"http://[::1/\\\"\", \"could not parse domain\" },\n\n        /* Multiple challenge failure cases: */\n        { \"Basic, Digest realm=\\\"foo\\\", algorithm=MD5, qop=auth\",\n          \"missing parameter in Digest challenge, missing realm in Basic challenge\" },\n        \n        { \"Digest realm=\\\"foo\\\", algorithm=MD5, qop=auth, nonce=\\\"foo\\\",\"\n          \" Basic realm=\\\"foo\\\"\",\n          \"rejected Digest challenge, rejected Basic challenge\" },\n\n        { \"WhizzBangAuth realm=\\\"foo\\\", \" \n          \"Basic realm='foo'\",\n          \"ignored WhizzBangAuth challenge, rejected Basic challenge\" },\n        { \"\", \"could not parse challenge\" },\n\n        /* neon 0.26.x regression in \"attempt\" handling. */\n        { \"Basic realm=\\\"foo\\\", \" \n          \"Digest realm=\\\"bar\\\", algorithm=MD5, qop=auth, nonce=\\\"foo\\\"\",\n          \"rejected Digest challenge, rejected Basic challenge\"\n          , \"<bar, 0><foo, 1>\"  /* Digest challenge first, Basic second. */\n        }\n    };\n    unsigned n;\n    \n    for (n = 0; n < sizeof(ts)/sizeof(ts[0]); n++) {\n        char resp[512];\n        ne_session *sess;\n        int ret;\n        ne_buffer *buf = ne_buffer_create();\n\n        ne_snprintf(resp, sizeof resp,\n                    \"HTTP/1.1 401 Auth Denied\\r\\n\"\n                    \"WWW-Authenticate: %s\\r\\n\"\n                    \"Content-Length: 0\\r\\n\" \"\\r\\n\",\n                    ts[n].resp);\n        \n        CALL(multi_session_server(&sess, \"http\",\n                                  2, single_serve_string, resp));\n\n        ne_add_server_auth(sess, NE_AUTH_ALL|NE_AUTH_LEGACY_DIGEST, fail_cb, buf);\n        \n        ret = any_2xx_request(sess, \"/fish\");\n        ONV(ret == NE_OK,\n            (\"request success (iter %u); expecting error '%s'\",\n             n, ts[n].error));\n\n        ONV(strstr(ne_get_error(sess), ts[n].error) == NULL,\n            (\"request fails with error '%s'; expecting '%s'\",\n             ne_get_error(sess), ts[n].error));\n        \n        if (ts[n].challs) {\n            ONCMP(ts[n].challs, buf->data, \"challenge callback\", \n                  \"invocation order\");\n        }\n\n        ne_session_destroy(sess);\n        ne_buffer_destroy(buf);\n        reap_server();\n    }\n\n    return OK;\n}\n\nstruct multi_context {\n    int id;\n    ne_buffer *buf;\n};\n\nstatic int multi_cb(void *userdata, const char *realm, int tries, \n                    char *un, char *pw)\n{\n    struct multi_context *ctx = userdata;\n\n    ne_buffer_snprintf(ctx->buf, 128, \"[id=%d, realm=%s, tries=%d]\", \n                       ctx->id, realm, tries);\n\n    return -1;\n}\n\nstatic int multi_handler(void)\n{\n    ne_session *sess;\n    struct multi_context c[2];\n    unsigned n;\n    ne_buffer *buf = ne_buffer_create();\n\n    CALL(make_session(&sess, single_serve_string,\n                      \"HTTP/1.1 401 Auth Denied\\r\\n\"\n                      \"WWW-Authenticate: Basic realm='fish',\"\n                      \" Digest realm='food', algorithm=MD5, qop=auth, nonce=gaga\\r\\n\"\n                      \"Content-Length: 0\\r\\n\" \"\\r\\n\"));\n    \n    for (n = 0; n < 2; n++) {\n        c[n].buf = buf;\n        c[n].id = n + 1;\n    }\n\n    ne_add_server_auth(sess, NE_AUTH_BASIC, multi_cb, &c[0]);\n    ne_add_server_auth(sess, NE_AUTH_DIGEST, multi_cb, &c[1]);\n    \n    any_request(sess, \"/fish\");\n    \n    ONCMP(\"[id=2, realm=food, tries=0]\"\n          \"[id=1, realm=fish, tries=0]\", buf->data,\n          \"multiple callback\", \"invocation order\");\n    \n    ne_buffer_destroy(buf);\n\n    return destroy_and_wait(sess);\n}\n\nstatic int multi_rfc7616(void)\n{\n    ne_session *sess;\n    struct multi_context c[2];\n    unsigned n;\n    ne_buffer *buf, *exp;\n\n    buf = ne_buffer_create();\n    CALL(make_session(&sess, single_serve_string,\n                      \"HTTP/1.1 401 Auth Denied\\r\\n\"\n                      \"WWW-Authenticate: \"\n                      \"Digest realm='sha512-realm', algorithm=SHA-512-256, qop=auth, nonce=gaga, \"\n                      \"Basic realm='basic-realm', \"\n                      \"Digest realm='md5-realm', algorithm=MD5, qop=auth, nonce=gaga, \"\n                      \"Digest realm='sha256-realm', algorithm=SHA-256, qop=auth, nonce=gaga\\r\\n\"\n                      \"Content-Length: 0\\r\\n\" \"\\r\\n\"));\n\n    for (n = 0; n < 2; n++) {\n        c[n].buf = buf;\n        c[n].id = n + 1;\n    }\n\n    ne_add_server_auth(sess, NE_AUTH_BASIC, multi_cb, &c[0]);\n    ne_add_server_auth(sess, NE_AUTH_DIGEST, multi_cb, &c[1]);\n\n    any_request(sess, \"/fish\");\n\n    exp = ne_buffer_create();\n    n = 0;\n    if (has_sha512_256)\n        ne_buffer_snprintf(exp, 100, \"[id=2, realm=sha512-realm, tries=%u]\", n++);\n    if (has_sha256)\n        ne_buffer_snprintf(exp, 100, \"[id=2, realm=sha256-realm, tries=%u]\", n++);\n    ne_buffer_snprintf(exp, 100,\n                       \"[id=2, realm=md5-realm, tries=%u]\"\n                       \"[id=1, realm=basic-realm, tries=0]\", n);\n    ONV(strcmp(exp->data, buf->data),\n        (\"unexpected callback ordering.\\n\"\n         \"expected: %s\\n\"\n         \"actual:   %s\\n\",\n         exp->data, buf->data));\n\n    ne_buffer_destroy(buf);\n    ne_buffer_destroy(exp);\n\n    return destroy_and_wait(sess);\n}\n\nstatic int multi_provider_cb(void *userdata, int attempt,\n                             unsigned protocol, const char *realm,\n                             char *un, char *pw, size_t buflen)\n{\n    ne_buffer *buf = userdata;\n    const char *ctx;\n\n    if (buflen == NE_ABUFSIZ) {\n        NE_DEBUG(NE_DBG_HTTPAUTH, \"auth: FAILED for short buffer length.\\n\");\n        return -1;\n    }\n\n    if ((protocol & NE_AUTH_PROXY) == NE_AUTH_PROXY) {\n        ctx = \"proxy\";\n        protocol ^= NE_AUTH_PROXY;\n    }\n    else {\n        ctx = \"server\";\n    }\n\n    ne_buffer_snprintf(buf, 128, \"[%s: proto=%u, realm=%s, attempt=%d]\",\n                       ctx, protocol, realm, attempt);\n\n    ne_strnzcpy(un, \"foo\", buflen);\n    ne_strnzcpy(pw, \"bar\", buflen);\n\n    return protocol == NE_AUTH_BASIC ? 0 : -1;\n}\n\nstatic int serve_provider(ne_socket *s, void *userdata)\n{\n    CALL(serve_response(s,\n                        \"HTTP/1.1 407 Proxy Auth Plz\\r\\n\"\n                        \"Proxy-Authenticate: Basic realm='proxy-realm'\\r\\n\"\n                        \"Content-Length: 0\\r\\n\" \"\\r\\n\"));\n    CALL(serve_response(s,\n                        \"HTTP/1.1 401 Auth Denied\\r\\n\"\n                        \"WWW-Authenticate: \"\n                        \"  Digest realm='sha512-realm', algorithm=SHA-512-256, qop=auth, nonce=gaga, \"\n                        \"  Basic realm='basic-realm', \"\n                        \"  Digest realm='md5-realm', algorithm=MD5, qop=auth, nonce=gaga, \"\n                        \"  Digest realm='sha256-realm', algorithm=SHA-256, qop=auth, nonce=gaga\\r\\n\"\n                        \"Content-Length: 0\\r\\n\" \"\\r\\n\"));\n    CALL(serve_response(s,\n                        \"HTTP/1.1 401 Auth Denied\\r\\n\"\n                        \"WWW-Authenticate: \"\n                        \"  Digest realm='sha512-realm', algorithm=SHA-512-256, qop=auth, nonce=gaga, \"\n                        \"  Basic realm='basic-realm'\\r\\n\"\n                        \"Content-Length: 0\\r\\n\" \"\\r\\n\"));\n    return serve_response(s,\n                          \"HTTP/1.1 200 OK\\r\\n\"\n                          \"Content-Length: 0\\r\\n\" \"\\r\\n\");\n}\n\nstatic int multi_provider(void)\n{\n    ne_session *sess;\n    ne_buffer *buf = ne_buffer_create(), *exp;\n\n    CALL(make_session(&sess, serve_provider, NULL));\n\n    ne_add_auth(sess, NE_AUTH_DIGEST|NE_AUTH_BASIC, multi_provider_cb, buf);\n\n    ONREQ(any_request(sess, \"/fish\"));\n\n    exp = ne_buffer_create();\n    ne_buffer_snprintf(exp, 100,\n                       \"[proxy: proto=%u, realm=proxy-realm, attempt=0]\",\n                       NE_AUTH_BASIC);\n    if (has_sha512_256)\n        ne_buffer_snprintf(exp, 100, \"[server: proto=%u, realm=sha512-realm, attempt=0]\",\n                           NE_AUTH_DIGEST);\n    if (has_sha256)\n        ne_buffer_snprintf(exp, 100, \"[server: proto=%u, realm=sha256-realm, attempt=0]\",\n                           NE_AUTH_DIGEST);\n    ne_buffer_snprintf(exp, 100,\n                       \"[server: proto=%u, realm=md5-realm, attempt=0]\"\n                       \"[server: proto=%u, realm=basic-realm, attempt=0]\",\n                       NE_AUTH_DIGEST, NE_AUTH_BASIC);\n\n    if (has_sha512_256)\n        ne_buffer_snprintf(exp, 100, \"[server: proto=%u, realm=sha512-realm, attempt=1]\",\n                           NE_AUTH_DIGEST);\n    ne_buffer_snprintf(exp, 100, \"[server: proto=%u, realm=basic-realm, attempt=1]\",\n                       NE_AUTH_BASIC);\n\n    ONV(strcmp(exp->data, buf->data),\n        (\"unexpected callback ordering.\\n\"\n         \"expected: %s\\n\"\n         \"actual:   %s\\n\",\n         exp->data, buf->data));\n\n    ne_buffer_destroy(buf);\n    ne_buffer_destroy(exp);\n\n    return destroy_and_wait(sess);\n}\n\n\nstatic int domains(void)\n{\n    ne_session *sess;\n    struct digest_parms parms;\n\n    memset(&parms, 0, sizeof parms);\n    parms.realm = \"WallyWorld\";\n    parms.flags = PARM_RFC2617;\n    parms.domain = \"http://localhost:4242/fish/ https://example.com /agaor /other\";\n    parms.num_requests = 6;\n\n    CALL(proxied_session_server(&sess, \"http\", \"localhost\", 4242,\n                                serve_digest, &parms));\n\n    ne_set_server_auth(sess, auth_cb, NULL);\n\n    CALL(any_2xx_request(sess, \"/fish/0\"));\n    CALL(any_2xx_request(sess, \"/outside\"));\n    CALL(any_2xx_request(sess, \"/others\"));\n    CALL(any_2xx_request(sess, \"/fish\"));\n    CALL(any_2xx_request(sess, \"/fish/2\"));\n    CALL(any_2xx_request(sess, \"*\"));\n    \n    return destroy_and_wait(sess);\n}\n\n/* This segfaulted with 0.28.0 through 0.28.2 inclusive. */\nstatic int CVE_2008_3746(void)\n{\n    ne_session *sess;\n    struct digest_parms parms;\n\n    memset(&parms, 0, sizeof parms);\n    parms.realm = \"WallyWorld\";\n    parms.flags = PARM_RFC2617;\n    parms.domain = \"foo\";\n    parms.num_requests = 1;\n\n    CALL(proxied_session_server(&sess, \"http\", \"www.example.com\", 80,\n                                serve_digest, &parms));\n\n    ne_set_server_auth(sess, auth_cb, NULL);\n\n    any_2xx_request(sess, \"/fish/0\");\n    \n    return destroy_and_wait(sess);\n}\n\nstatic int defaults(void)\n{\n    ne_session *sess;\n    \n    CALL(make_session(&sess, auth_serve, CHAL_WALLY));\n    ne_add_server_auth(sess, NE_AUTH_DEFAULT, auth_cb, NULL);\n    CALL(any_2xx_request(sess, \"/norman\"));\n    ne_session_destroy(sess);\n    CALL(await_server());\n\n    CALL(make_session(&sess, auth_serve, CHAL_WALLY));\n    ne_add_server_auth(sess, NE_AUTH_ALL, auth_cb, NULL);\n    CALL(any_2xx_request(sess, \"/norman\"));\n\n    return destroy_and_wait(sess);\n}\n\nstatic void fail_hdr(char *value)\n{\n    auth_failed = 1;\n}\n\nstatic int serve_forgotten(ne_socket *sock, void *userdata)\n{\n    auth_failed = 0;\n    got_header = fail_hdr;\n    want_header = \"Authorization\";\n    \n    CALL(discard_request(sock));\n    if (auth_failed) {\n        /* Should not get initial Auth header.  Eek. */\n        send_response(sock, NULL, 403, 1);\n        return 0;\n    }\n    send_response(sock, CHAL_WALLY, 401, 0);\n    \n    got_header = auth_hdr;\n    CALL(discard_request(sock));\n    if (auth_failed) {\n        send_response(sock, NULL, 403, 1);\n        return 0;\n    }\n    send_response(sock, NULL, 200, 0);\n    \n    ne_sock_read_timeout(sock, 5);\n\n    /* Last time; should get no Auth header. */\n    got_header = fail_hdr;\n    CALL(discard_request(sock));\n    send_response(sock, NULL, auth_failed ? 500 : 200, 1);\n    \n    return 0;                  \n}\n\nstatic int forget(void)\n{\n    ne_session *sess;\n\n    CALL(make_session(&sess, serve_forgotten, NULL));\n\n    ne_set_server_auth(sess, auth_cb, NULL);\n    CALL(any_2xx_request(sess, \"/norman\"));\n    \n    ne_forget_auth(sess);\n    CALL(any_2xx_request(sess, \"/norman\"));\n\n    return destroy_and_wait(sess);\n}\n\nstatic int serve_basic_scope_checker(ne_socket *sock, void *userdata)\n{\n    /* --- GET /fish/0.txt -- first request */\n    digest_hdr = NULL;\n    got_header = dup_header;\n    want_header = \"Authorization\";\n    CALL(discard_request(sock));\n    if (digest_hdr) {\n        t_context(\"Got WWW-Auth header on initial request\");\n        return error_response(sock, FAIL);\n    }\n\n    send_response(sock, CHAL_WALLY, 401, 0);\n\n    /* Retry of GET /fish/0 - expect Basic creds */\n    auth_failed = 1;\n    got_header = auth_hdr;\n    CALL(discard_request(sock));\n    if (auth_failed) {\n        t_context(\"bad Basic Auth on first request\");\n        return error_response(sock, FAIL);\n    }\n    send_response(sock, CHAL_WALLY, 200, 0);\n    \n    /* --- GET /not/inside -- second request */\n    got_header = dup_header;\n    CALL(discard_request(sock));\n    if (digest_hdr) {\n        t_context(\"Basic auth sent outside of credentials scope\");\n        return error_response(sock, FAIL);\n    }\n    send_response(sock, CHAL_WALLY, 200, 0);\n\n    /* --- GET /fish/1 -- third request */\n    got_header = auth_hdr;\n    CALL(discard_request(sock));\n    send_response(sock, NULL, auth_failed?500:200, 1);\n    \n    return 0;    \n}\n\n/* Check that Basic auth follows the RFC7617 rules around scope. */\nstatic int basic_scope(void)\n{\n    ne_session *sess;\n\n    CALL(make_session(&sess, serve_basic_scope_checker, NULL));\n\n    ne_set_server_auth(sess, auth_cb, NULL);\n    \n    CALL(any_2xx_request(sess, \"/fish/0.txt\")); /* must use auth */\n    CALL(any_2xx_request(sess, \"/not/inside\")); /* must NOT use auth credentials */\n    CALL(any_2xx_request(sess, \"/fish/1\")); /* must use auth credentials */\n\n    return destroy_and_wait(sess);\n}\n\n/* Test for scope of \"*\" */\nstatic int serve_star_scope_checker(ne_socket *sock, void *userdata)\n{\n    /* --- OPTIONS * -- first request */\n    digest_hdr = NULL;\n    got_header = dup_header;\n    want_header = \"Authorization\";\n    CALL(discard_request(sock));\n    if (digest_hdr) {\n        t_context(\"Got WWW-Auth header on initial request\");\n        return error_response(sock, FAIL);\n    }\n\n    send_response(sock, CHAL_WALLY, 401, 0);\n\n    /* Retry of OPTIONS * - expect Basic creds */\n    auth_failed = 1;\n    got_header = auth_hdr;\n    CALL(discard_request(sock));\n    if (auth_failed) {\n        t_context(\"No Basic Auth in OPTIONS request\");\n        return error_response(sock, FAIL);\n    }\n    send_response(sock, CHAL_WALLY, 200, 0);\n\n    return 0;\n}\n\n/* Test for the scope of \"*\". */\nstatic int star_scope(void)\n{\n    ne_session *sess;\n\n    CALL(make_session(&sess, serve_star_scope_checker, NULL));\n\n    ne_set_server_auth(sess, auth_cb, NULL);\n\n    CALL(any_2xx_request_method(sess, \"OPTIONS\", \"*\")); /* must use auth */\n\n    return destroy_and_wait(sess);\n}\n\n/* Test for realm with non-readable characters. */\nstatic int serve_unclean_realm(ne_socket *sock, void *userdata)\n{\n    CALL(discard_request(sock));\n    send_response(sock, \"WWW-Authenticate: Basic realm='Foo\\tBar'\", 401, 0);\n\n    CALL(discard_request(sock));\n    send_response(sock, NULL, 200, 0);\n\n    return 0;\n}\n\nstatic int get_realm_cb(void *userdata, const char *realm, int tries, \n                        char *un, char *pw)\n{\n    char **rp = userdata;\n\n    *rp = ne_strdup(realm);\n\n    ne_strnzcpy(un, \"foo\", NE_ABUFSIZ);\n    ne_strnzcpy(pw, \"bar\", NE_ABUFSIZ);\n\n    return 0;\n}\n\n/* Test for the scope of \"*\". */\nstatic int clean_realm(void)\n{\n    ne_session *sess;\n    char *realm = NULL;\n\n    CALL(make_session(&sess, serve_unclean_realm, NULL));\n\n    ne_set_server_auth(sess, get_realm_cb, &realm);\n\n    ONREQ(any_request(sess, \"/realm-test\"));\n\n    ONN(\"no realm header found?\", realm == NULL);\n\n    ONV(strchr(realm, '\\t') != NULL,\n        (\"realm header returned unclean: '%s'\", realm));\n\n    ne_free(realm);\n\n    return destroy_and_wait(sess);\n}\n\n#ifdef TEST_NTLM\n\nstatic char *ntlm_auth_hdr = NULL;\n\nstatic void capture_ntlm_hdr(char *value)\n{\n    if (ntlm_auth_hdr) ne_free(ntlm_auth_hdr);\n    ntlm_auth_hdr = ne_strdup(value);\n}\n\n/* Helper to build a Type 2 NTLM challenge message, this is not\n * supported via the libntlm. */\nstatic int build_type2_challenge(tSmbNtlmAuthChallenge *challenge,\n                                 const char *domain,\n                                 unsigned char nonce[8])\n{\n    memset(challenge, 0, sizeof(*challenge));\n\n    memcpy(challenge->ident, \"NTLMSSP\\0\", 8);\n    challenge->msgType = htole32(2);\n    challenge->flags = htole32(0x00008201);\n\n    /* Set the challenge nonce */\n    memcpy(challenge->challengeData, nonce, 8);\n\n    /* Set domain in Unicode */\n    if (domain && *domain) {\n        unsigned i;\n\n        for (i = 0; i < strlen(domain) && i < (NTLM_MSG_BUFSIZE/2 - 1); i++) {\n            challenge->buffer[i*2] = domain[i];\n            challenge->buffer[i*2+1] = 0;\n        }\n        challenge->uDomain.len = htole16(i * 2);\n        challenge->uDomain.maxlen = htole16(i * 2);\n        challenge->uDomain.offset = htole32((unsigned char *)challenge->buffer - (unsigned char *)challenge);\n        challenge->bufIndex = htole32(i * 2);\n    }\n\n    return OK;\n}\n\n/* Server function for NTLM auth handling. */\nstatic int serve_ntlm(ne_socket *sock, void *userdata)\n{\n    tSmbNtlmAuthRequest request;\n    tSmbNtlmAuthChallenge challenge;\n    tSmbNtlmAuthResponse response;\n    char resp[NE_BUFSIZ];\n    char *type2_b64;\n    unsigned char *type1_buf = NULL;\n    unsigned char *type3_buf = NULL;\n    size_t type1_size, type3_size, type2_size;\n    unsigned char nonce[8];\n\n    ONN(\"could not generate nonce\", ne_mknonce(nonce, sizeof nonce, 0));\n\n    want_header = \"Authorization\";\n    got_header = capture_ntlm_hdr;\n    ntlm_auth_hdr = NULL;\n\n    /* Request 1: No auth expected, send NTLM challenge */\n    CALL(discard_request(sock));\n    ONV(ntlm_auth_hdr != NULL,\n        (\"got unexpected Authorization header on first request: %s\", ntlm_auth_hdr));\n\n    ne_snprintf(resp, sizeof resp,\n                \"HTTP/1.1 401 Unauthorized\\r\\n\"\n                \"WWW-Authenticate: NTLM\\r\\n\"\n                \"Content-Length: 0\\r\\n\\r\\n\");\n    SEND_STRING(sock, resp);\n\n    /* Request 2: Expect Type 1 message, send Type 2 challenge */\n    CALL(discard_request(sock));\n    ONN(\"no Authorization header on second request\", ntlm_auth_hdr == NULL);\n\n    /* Verify it starts with \"NTLM \" */\n    ONV(strncmp(ntlm_auth_hdr, \"NTLM \", 5) != 0,\n        (\"Authorization header doesn't start with 'NTLM ': %s\", ntlm_auth_hdr));\n\n    /* Decode and validate Type 1 message */\n    type1_size = ne_unbase64(ntlm_auth_hdr + 5, &type1_buf);\n    ONV(type1_size < 32,\n        (\"Type 1 message too short: %lu bytes\", type1_size));\n\n    if (type1_size >= 32) {\n        size_t copy_size = type1_size < sizeof(request) ? type1_size : sizeof(request);\n        memcpy(&request, type1_buf, copy_size);\n\n        ONV(memcmp(request.ident, \"NTLMSSP\\0\", 8) != 0,\n            (\"Type 1 message has invalid NTLMSSP signature\"));\n        ONV(le32toh(request.msgType) != 1,\n            (\"Type 1 message has wrong type: %u (expected 1)\", le32toh(request.msgType)));\n\n        NE_DEBUG(NE_DBG_HTTP, \"auth: Valid Type 1 message received.\\n\");\n#ifdef NE_DEBUGGING\n        dumpSmbNtlmAuthRequest(ne_debug_stream, &request);\n#endif\n    }\n\n    if (type1_buf) ne_free(type1_buf);\n    if (ntlm_auth_hdr) ne_free(ntlm_auth_hdr);\n    ntlm_auth_hdr = NULL;\n\n    /* Build Type 2 challenge */\n    build_type2_challenge(&challenge, \"DOMAIN\", nonce);\n    NE_DEBUG(NE_DBG_HTTP, \"auth: Sending Type 2 challenge:\\n\");\n#ifdef NE_DEBUGGING\n    dumpSmbNtlmAuthChallenge(ne_debug_stream, &challenge);\n#endif\n\n    /* Calculate size using the SmbLength macro */\n    type2_size = SmbLength(&challenge);\n    type2_b64 = ne_base64((unsigned char *)&challenge, type2_size);\n    ne_snprintf(resp, sizeof resp,\n                \"HTTP/1.1 401 Unauthorized\\r\\n\"\n                \"WWW-Authenticate: NTLM %s\\r\\n\"\n                \"Content-Length: 0\\r\\n\\r\\n\", type2_b64);\n    ne_free(type2_b64);\n    SEND_STRING(sock, resp);\n\n    /* Request 3: Expect Type 3 response, validate and send 200 */\n    CALL(discard_request(sock));\n    ONN(\"no Authorization header on third request\", ntlm_auth_hdr == NULL);\n\n    /* Verify it starts with \"NTLM \" */\n    ONV(strncmp(ntlm_auth_hdr, \"NTLM \", 5) != 0,\n        (\"Authorization header doesn't start with 'NTLM ': %s\", ntlm_auth_hdr));\n\n    /* Decode and validate Type 3 message */\n    type3_size = ne_unbase64(ntlm_auth_hdr + 5, &type3_buf);\n    ONV(type3_size < 52 || type3_size > sizeof response,\n        (\"Type 3 message too short/long: %\" NE_FMT_SIZE_T \" bytes\", type3_size));\n\n    memcpy(&response, type3_buf, type3_size);\n\n    ONV(memcmp(response.ident, \"NTLMSSP\\0\", 8) != 0,\n        (\"Type 3 message has invalid NTLMSSP signature\"));\n    ONV(le32toh(response.msgType) != 3,\n        (\"Type 3 message has wrong type: %u (expected 3)\", le32toh(response.msgType)));\n    \n    /* Validate security buffers have reasonable values */\n    ONV(response.lmResponse.len > 24 && response.lmResponse.len != 24,\n        (\"Type 3 LM response length invalid: %u\", response.lmResponse.len));\n    ONV(response.ntResponse.len != 24 && response.ntResponse.len != 0,\n        (\"Type 3 NT response length invalid: %u\", response.ntResponse.len));\n\n    /* Check that offsets are within message bounds */\n    ONV(response.lmResponse.offset >= type3_size,\n        (\"Type 3 LM response offset out of bounds: %u >= %lu\",\n         response.lmResponse.offset, type3_size));\n    ONV(response.ntResponse.offset >= type3_size,\n        (\"Type 3 NT response offset out of bounds: %u >= %lu\",\n         response.ntResponse.offset, type3_size));\n\n    NE_DEBUG(NE_DBG_HTTP, \"auth: Valid Type 3 message received -- \\n\");\n#ifdef NE_DEBUGGING\n    dumpSmbNtlmAuthResponse(ne_debug_stream, &response);\n#endif\n\n    if (type3_buf) ne_free(type3_buf);\n    if (ntlm_auth_hdr) ne_free(ntlm_auth_hdr);\n    ntlm_auth_hdr = NULL;\n\n    /* Send success response */\n    ne_snprintf(resp, sizeof resp,\n                \"HTTP/1.1 200 OK\\r\\n\"\n                \"Content-Length: 0\\r\\n\\r\\n\");\n    SEND_STRING(sock, resp);\n\n    return OK;\n}\n\nstatic int ntlm_cb(void *userdata, const char *realm, int tries,\n                   char *un, char *pw)\n{\n    strcpy(un, \"user@MYDOMAIN\");\n    strcpy(pw, \"SecREt01\");\n    return tries;\n}\n\n/* Test NTLM authentication with server handshake */\nstatic int ntlm(void)\n{\n    ne_session *sess;\n\n    CALL(make_session(&sess, serve_ntlm, NULL));\n    ne_add_server_auth(sess, NE_AUTH_NTLM, ntlm_cb, NULL);\n\n    CALL(any_2xx_request(sess, \"/ntlm-test\"));\n\n    return destroy_and_wait(sess);\n}\n#endif\n\n/* proxy auth, proxy AND origin */\n\nne_test tests[] = {\n    T(init),\n    T(basic),\n    T(retries),\n    T(forget_regress),\n    T(tunnel_regress),\n    T(negotiate_regress),\n    T(digest),\n    T(digest_sha256),\n    T(digest_sha512_256),\n    T(digest_failures),\n    T(digest_username_star),\n    T(fail_challenge),\n    T(multi_handler),\n    T(multi_rfc7616),\n    T(multi_provider),\n    T(domains),\n    T(defaults),\n    T(CVE_2008_3746),\n    T(forget),\n    T(basic_scope),\n    T(star_scope),\n    T(clean_realm),\n#ifdef TEST_NTLM\n    T(ntlm),\n#endif\n    T(NULL)\n};\n"
  },
  {
    "path": "test/basic.c",
    "content": "/* \n   Tests for high-level HTTP interface (ne_basic.h)\n   Copyright (C) 2002-2008, 2012, Joe Orton <joe@manyfish.co.uk>\n\n   This program is free software; you can redistribute it and/or modify\n   it under the terms of the GNU General Public License as published by\n   the Free Software Foundation; either version 2 of the License, or\n   (at your option) any later version.\n  \n   This program is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU General Public License for more details.\n  \n   You should have received a copy of the GNU General Public License\n   along with this program; if not, write to the Free Software\n   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\n*/\n\n#include \"config.h\"\n\n#include <sys/types.h>\n\n#ifdef HAVE_STDLIB_H\n#include <stdlib.h>\n#endif\n#ifdef HAVE_UNISTD_H\n#include <unistd.h>\n#endif\n\n#include <fcntl.h>\n\n#include \"ne_basic.h\"\n\n#include \"tests.h\"\n#include \"child.h\"\n#include \"utils.h\"\n\nstatic int content_type(void)\n{\n    int n;\n    static const struct {\n\tconst char *value, *type, *subtype, *charset;\n    } ctypes[] = {\n\t{ \"foo/bar\", \"foo\", \"bar\", NULL },\n\t{ \"foo/bar  \", \"foo\", \"bar\", NULL },\n\t{ \"application/xml\", \"application\", \"xml\", NULL },\n        /* these rules previously applied RFC 3023, now updated for 7303. */\n        { \"text/lemon\", \"text\", \"lemon\", NULL },\n        { \"text/xml\", \"text\", \"xml\", NULL },\n#undef TXU\n#define TXU \"text\", \"xml\", \"utf-8\"\n\t/* 2616 doesn't *say* that charset can be quoted, but bets are\n\t * that some servers do it anyway. */\n\t{ \"text/xml; charset=utf-8\", TXU },\n\t{ \"TEXT/XML; charset=utf-8\", TXU },\n\t{ \"tExT/xMl; ChaRSet='utf-8'\", TXU },\n\t{ \"text/xml; charset=utf-8; foo=bar\", TXU },\n\t{ \"text/xml;charset=utf-8\", TXU },\n\t{ \"text/xml ;charset=utf-8\", TXU },\n\t{ \"text/xml; bleee; charset=utf-8;foo=bar\", TXU },\n\t{ \"text/xml; foo=bar;  charset = utf-8; foo=bar\", TXU },\n\t{ \"text/xml; foo=bar; charset=utf-8; bar=foo\", TXU },\n\t{ \"text/xml; charset=\\\"utf-8\\\"\", TXU },\n\t{ \"text/xml; charset='utf-8'\", TXU },\n\t{ \"text/xml; foo=bar; charset=\\\"utf-8\\\"; bar=foo\", TXU },\n#undef TXU\n\t/* badly quoted charset should come out as NULL */\n\t{ \"foo/lemon; charset=\\\"utf-8\", \"foo\", \"lemon\", NULL },\n\t{ NULL }\n    };\n\n    for (n = 0; ctypes[n].value != NULL; n++) {\n        ne_content_type ct;\n        ne_session *sess;\n        ne_request *req;\n        char resp[200];\n        int rv;\n\n        ct.type = ct.subtype = ct.charset = ct.value = \"unset\";\n\n        ne_snprintf(resp, sizeof resp,\n                    \"HTTP/1.0 200 OK\\r\\n\" \"Content-Length: 0\\r\\n\"\n                    \"Content-Type: %s\\r\\n\" \"\\r\\n\", ctypes[n].value);\n        \n        CALL(make_session(&sess, single_serve_string, resp));\n\n        req = ne_request_create(sess, \"GET\", \"/anyfoo\");\n        ONREQ(ne_request_dispatch(req));\n        rv = ne_get_content_type(req, &ct);\n        \n        ONV(rv == 0 && !ctypes[n].type,\n            (\"expected c-t parse failure for %s\", ctypes[n].value));\n\n        ONV(rv != 0 && ctypes[n].type,\n            (\"c-t parse failure %d for %s\", rv, ctypes[n].value));\n\n        ne_request_destroy(req);\n        ne_session_destroy(sess);\n        CALL(await_server());\n\n        if (rv) continue;\t\n\n\tONV(strcmp(ct.type, ctypes[n].type),\n\t    (\"for `%s': type was `%s'\", ctypes[n].value, ct.type));\n\n\tONV(strcmp(ct.subtype, ctypes[n].subtype),\n\t    (\"for `%s': subtype was `%s'\", ctypes[n].value, ct.subtype));\n\n\tONV(ctypes[n].charset && ct.charset == NULL,\n\t    (\"for `%s': charset unset\", ctypes[n].value));\n\t\n\tONV(ctypes[n].charset == NULL && ct.charset != NULL,\n\t    (\"for `%s': unexpected charset `%s'\", ctypes[n].value, \n\t     ct.charset));\n\n\tONV(ctypes[n].charset && ct.charset &&\n\t    strcmp(ctypes[n].charset, ct.charset),\n\t    (\"for `%s': charset was `%s'\", ctypes[n].value, ct.charset));\n\n\tne_free(ct.value);\n    }\n\n    return OK;\n}\n\n/* Do ranged GET for range 'start' to 'end'; with 'resp' as response.\n * If 'fail' is non-NULL, expect ne_get_range to fail, and fail the\n * test with given message if it doesn't. */\nstatic int do_range(off_t start, off_t end, const char *fail,\n\t\t    const char *resp)\n{\n    ne_session *sess;\n    ne_content_range range = {0};\n    int fd, ret;\n\n    CALL(make_session(&sess, single_serve_string, (void *)resp));\n    \n    range.start = start;\n    range.end = end;\n    \n    fd = open(\"/dev/null\", O_WRONLY);\n    \n    ret = ne_get_range(sess, \"/foo\", &range, fd);\n\n    close(fd);\n    ne_close_connection(sess);\n    CALL(await_server());\n    \n    if (fail) {\n#if 0\n\tt_warning(\"error was %s\", ne_get_error(sess));\n#endif\n\tONV(ret == NE_OK, (\"%s\", fail));\n    } else {\n\tONREQ(ret);\n    }\n    \n    ne_session_destroy(sess);\n    return OK;\n}\n\nstatic int get_range(void)\n{\n    struct {\n        off_t start, end;\n        const char *expected_error, *response;\n    } ts[] = {\n        {\n            1, 10, NULL,\n            \"HTTP/1.1 206 Widgets\\r\\n\"\n            \"Connection: close\\r\\n\"\n            \"Content-Range: bytes 1-10/10\\r\\n\"\n            \"Content-Length: 10\\r\\n\\r\\nabcdefghij\"\n        },\n        {\n            1, -1, NULL,\n            \"HTTP/1.1 206 Widgets\\r\\n\"\n            \"Connection: close\\r\\n\"\n            \"Content-Range: bytes 1-10/10\\r\\n\"\n            \"Content-Length: 10\\r\\n\\r\\nabcdefghij\"\n        },\n        {\n            1, 10, \"range response length mismatch should fail\",\n            \"HTTP/1.1 206 Widgets\\r\\n\"\n            \"Connection: close\\r\\n\"\n            \"Content-Range: bytes 1-2/2\\r\\n\"\n            \"Content-Length: 2\\r\\n\\r\\nab\"\n        },\n        {\n            1, 2, \"range response units check should fail\",\n            \"HTTP/1.1 206 Widgets\\r\\n\"\n            \"Connection: close\\r\\n\"\n            \"Content-Range: fish 1-2/2\\r\\n\"\n            \"Content-Length: 2\\r\\n\\r\\nab\"\n        },\n        {\n            1, 2, \"non-ranged response should fail\",\n            \"HTTP/1.1 200 Widgets\\r\\n\"\n            \"Connection: close\\r\\n\"\n            \"Content-Range: bytes 1-2/2\\r\\n\"\n            \"Content-Length: 2\\r\\n\\r\\nab\"\n        },\n        {\n            1, 2, \"unsatisfiable range should fail\",\n            \"HTTP/1.1 416 No Go\\r\\n\"\n            \"Connection: close\\r\\n\"\n            \"Content-Length: 2\\r\\n\\r\\nab\"\n        }\n    };\n    unsigned i;\n\n    for (i = 0; i < sizeof(ts) / sizeof(ts[0]); i++) {\n        CALL(do_range(ts[i].start, ts[i].end,\n                      ts[i].expected_error, ts[i].response));\n    }\n\n    return OK;\n}\n\nstatic int dav_capabilities(void)\n{\n    static const struct {\n\tconst char *hdrs;\n\tunsigned int class1, class2, exec;\n    } caps[] = {\n\t{ \"DAV: 1,2\\r\\n\", 1, 1, 0 },\n\t{ \"DAV: 1 2\\r\\n\", 0, 0, 0 },\n\t/* these aren't strictly legal DAV: headers: */\n\t{ \"DAV: 2,1\\r\\n\", 1, 1, 0 },\n\t{ \"DAV:  1, 2  \\r\\n\", 1, 1, 0 },\n\t{ \"DAV: 1\\r\\nDAV:2\\r\\n\", 1, 1, 0 },\n\t{ NULL, 0, 0, 0 }\n    };\n    char resp[BUFSIZ];\n    int n;\n\n    for (n = 0; caps[n].hdrs != NULL; n++) {\n\tne_server_capabilities c = {0};\n\tne_session *sess;\n\n\tne_snprintf(resp, BUFSIZ, \"HTTP/1.0 200 OK\\r\\n\"\n\t\t    \"Connection: close\\r\\n\"\n\t\t    \"%s\" \"\\r\\n\", caps[n].hdrs);\n\n\tCALL(make_session(&sess, single_serve_string, resp));\n\n\tONREQ(ne_options(sess, \"/foo\", &c));\n\n\tONV(c.dav_class1 != caps[n].class1,\n\t    (\"class1 was %d not %d\", c.dav_class1, caps[n].class1));\n\tONV(c.dav_class2 != caps[n].class2,\n\t    (\"class2 was %d not %d\", c.dav_class2, caps[n].class2));\n\tONV(c.dav_executable != caps[n].exec,\n\t    (\"class2 was %d not %d\", c.dav_executable, caps[n].exec));\n\n\tCALL(destroy_and_wait(sess));\n    }\n\n    return OK;\t\n}\n\nstatic int get(void)\n{\n    ne_session *sess;\n    int fd;\n    \n    CALL(make_session(&sess, single_serve_string, \n                      \"HTTP/1.0 200 OK\\r\\n\"\n                      \"Content-Length: 5\\r\\n\"\n                      \"\\r\\n\"\n                      \"abcde\"));\n    \n    fd = open(\"/dev/null\", O_WRONLY);\n    ONREQ(ne_get(sess, \"/getit\", fd));\n    close(fd);\n\n    return destroy_and_wait(sess);\n}\n\n\n#define CHUNK(len, data) #len \"\\r\\n\" data \"\\r\\n\"\n\n#define ABCDE_CHUNKS CHUNK(1, \"a\") CHUNK(1, \"b\") \\\n CHUNK(1, \"c\") CHUNK(1, \"d\") \\\n CHUNK(1, \"e\") CHUNK(0, \"\")\n\nstatic int getbuf(void)\n{\n    ne_session *sess;\n    char buffer[16];\n    size_t buflen = sizeof buffer;\n\n    CALL(make_session(&sess, single_serve_string,\n                      \"HTTP/1.1 200 OK\\r\\n\" \"Server: neon-test-server\\r\\n\"\n                      \"Transfer-Encoding: chunked\\r\\n\"\n                      \"\\r\\n\"\n                      ABCDE_CHUNKS));\n\n    ONREQ(ne_getbuf(sess, \"/\", buffer, &buflen));\n\n    ONV(buflen != 5, (\"unexpected buffer length %\" NE_FMT_SIZE_T, buflen));\n\n    ONV(memcmp(\"abcde\", buffer, 5) != 0,\n        (\"mismatched chunked response: [%5s]\", buffer));\n\n    return destroy_and_wait(sess);\n}\n\nstatic int getbuf_fail(void)\n{\n    ne_session *sess;\n    char buffer[16];\n    size_t buflen = sizeof buffer;\n    int ret;\n\n    CALL(make_session(&sess, single_serve_string,\n                      \"HTTP/1.1 302 OK\\r\\n\" \"Server: neon-test-server\\r\\n\"\n                      \"Transfer-Encoding: chunked\\r\\n\"\n                      \"\\r\\n\"\n                      ABCDE_CHUNKS));\n\n    ret = ne_getbuf(sess, \"/\", buffer, &buflen);\n    ONN(\"success for non-2xx response\", ret != NE_ERROR);\n\n    ONV(buflen != sizeof buffer,\n        (\"buffer length adjusted to %\" NE_FMT_SIZE_T, buflen));\n\n    return destroy_and_wait(sess);\n}\n\nstatic int getbuf_fill(void)\n{\n    ne_session *sess;\n    char buffer[5];\n    size_t buflen = sizeof buffer;\n\n    CALL(make_session(&sess, single_serve_string,\n                      \"HTTP/1.1 200 OK\\r\\n\" \"Server: neon-test-server\\r\\n\"\n                      \"Transfer-Encoding: chunked\\r\\n\"\n                      \"\\r\\n\"\n                      ABCDE_CHUNKS));\n\n    ONREQ(ne_getbuf(sess, \"/\", buffer, &buflen));\n\n    ONV(buflen != 5, (\"unexpected buffer length %\" NE_FMT_SIZE_T, buflen));\n\n    ONV(memcmp(\"abcde\", buffer, 5) != 0,\n        (\"mismatched chunked response: [%5s]\", buffer));\n\n    return destroy_and_wait(sess);\n}\n\nstatic int getbuf2(void)\n{\n    ne_session *sess;\n    char buf;\n    size_t buflen = sizeof buf;\n    int ret;\n\n    CALL(make_session(&sess, single_serve_string,\n                      \"HTTP/1.1 200 OK\\r\\n\" \"Server: neon-test-server\\r\\n\"\n                      \"Content-Length: 5\\r\\n\"\n                      \"\\r\\n\"\n                      \"abcde\"\n                      \"HTTP/1.1 200 OK\\r\\n\" \"Server: neon-test-server\\r\\n\"\n                      \"Content-Length: 5\\r\\n\"\n                      \"\\r\\n\"\n                      \"abcde\"));\n\n    ret = ne_getbuf(sess, \"/\", &buf, &buflen);\n    ONV(ret != NE_FAILED, (\"overflow case gave %d not FAILED\", ret));\n    ONV(buflen != 1, (\"buffer length returned as %\" NE_FMT_SIZE_T, buflen));\n\n    ret = any_request(sess, \"/closeme\");\n    ONN(\"failed to close connection\", ret != NE_CONNECT);\n\n    return destroy_and_wait(sess);\n}\n\nstatic int post_getbuf_retry(ne_request *req, void *userdata, \n                           const ne_status *status)\n{\n    return status->code == 401 ? NE_RETRY : NE_OK;    \n}\n\nstatic int getbuf_retry(void)\n{\n    ne_session *sess;\n    char buf[6] = \"00000\";\n    size_t buflen = sizeof buf;\n\n    CALL(make_session(&sess, single_serve_string,\n                      \"HTTP/1.1 401 Retry Please\\r\\n\" \"Server: neon-test-server\\r\\n\"\n                      \"Content-Length: 8\\r\\n\"\n                      \"\\r\\n\"\n                      \"zzzzzzzz\"\n                      \"HTTP/1.1 200 OK\\r\\n\" \"Server: neon-test-server\\r\\n\"\n                      \"Content-Length: 1\\r\\n\"\n                      \"\\r\\n\"\n                      \"a\"));\n\n    ne_hook_post_send(sess, post_getbuf_retry, NULL);\n    \n    ONREQ(ne_getbuf(sess, \"/\", buf, &buflen));\n    ONV(buflen != 1, (\"buffer length returned as %\" NE_FMT_SIZE_T, buflen));\n\n    ONN(\"failed to close connection\", any_request(sess, \"/closeme\") != NE_CONNECT);\n\n    return destroy_and_wait(sess);\n}\n\n#define CLASS_12 (NE_CAP_DAV_CLASS1 | NE_CAP_DAV_CLASS2)\n\nstatic int options2(void)\n{\n    static const struct {\n        const char *hdrs;\n        unsigned int caps;\n    } ts[] = {\n        { \"1,2\\r\\n\", CLASS_12 },\n        { \"1 2\\r\\n\", 0 },\n        /* these aren't strictly legal headers: */\n        { \"2,1\\r\\n\", CLASS_12 },\n        { \" 1, 2  \\r\\n\", CLASS_12 },\n        { \"1\\r\\nDAV:2\\r\\n\", CLASS_12 },\n        /* extended types */\n        { \"1, 2, extended-mkcol\", CLASS_12 | NE_CAP_EXT_MKCOL },\n        { NULL, 0 }\n    };\n    char resp[BUFSIZ];\n    int n;\n\n    for (n = 0; ts[n].hdrs != NULL; n++) {\n        ne_session *sess;\n        unsigned int caps;\n\n        ne_snprintf(resp, BUFSIZ, \"HTTP/1.0 200 OK\\r\\n\"\n                    \"Connection: close\\r\\n\"\n                    \"Content-Length: 0\\r\\n\"\n                    \"DAV: %s\" \"\\r\\n\\r\\n\", ts[n].hdrs);\n\n        CALL(make_session(&sess, single_serve_string, resp));\n\n        ONREQ(ne_options2(sess, \"/foo\", &caps));\n\n        ONV(caps != ts[n].caps,\n            (\"capabilities for 'DAV: %s' were 0x%x, expected 0x%x\", \n             ts[n].hdrs, caps, ts[n].caps));\n\n        CALL(destroy_and_wait(sess));\n    }\n\n    return OK;  \n}\n\nstatic int put(void)\n{\n    ne_session *sess;\n    \n    CALL(make_session(&sess, single_serve_string, \"HTTP/1.1 204 OK\\r\\n\"\n                      \"Content-Length: 200\\r\\n\"\n                      \"\\r\\n\"));\n    \n    ONREQ(ne_putbuf(sess, \"/foo\", \"foobar\", 6));\n\n    return destroy_and_wait(sess);\n}\n\nstatic int getmodtime(void)\n{\n    static const struct {\n        const char *header;\n        time_t expected;\n    } ts[] = {\n        { \"Last-Modified: Sun, 06 Nov 1994 08:49:37 GMT\\r\\n\", 784111777 },\n        { \"Last-Modified: Sunday, 06-Nov-94 08:49:37 GMT\\r\\n\", 784111777 },\n        { \"Last-Modified: Sun Nov  6 08:49:37 1994\\r\\n\", 784111777 },\n        /* Missing header => -1 */\n        { \"\", -1 },\n        /* Invalid date => -1 */\n        { \"Last-Modified: not a valid date\\r\\n\", -1 },\n        { NULL, 0 }\n    };\n    int n;\n\n    for (n = 0; ts[n].header != NULL; n++) {\n        ne_session *sess;\n        char resp[BUFSIZ];\n        time_t modtime = 0;\n\n        ne_snprintf(resp, BUFSIZ,\n                    \"HTTP/1.1 200 OK\\r\\n\"\n                    \"Content-Length: 0\\r\\n\"\n                    \"%s\"\n                    \"\\r\\n\", ts[n].header);\n\n        CALL(make_session(&sess, single_serve_string, resp));\n\n        ONREQ(ne_getmodtime(sess, \"/foo\", &modtime));\n\n        ONV(modtime != ts[n].expected,\n            (\"for '%s': modtime was %ld, expected %ld\",\n             ts[n].header, (long)modtime, (long)ts[n].expected));\n\n        CALL(destroy_and_wait(sess));\n    }\n\n    return OK;\n}\n\nne_test tests[] = {\n    T(lookup_localhost),\n    T(content_type),\n    T(get_range),\n    T(dav_capabilities),\n    T(get),\n    T(getbuf),\n    T(getbuf_fail),\n    T(getbuf_fill),\n    T(getbuf2),\n    T(getbuf_retry),\n    T(options2),\n    T(put),\n    T(getmodtime),\n    T(NULL) \n};\n\n"
  },
  {
    "path": "test/checksyms.sh",
    "content": "#!/bin/bash -e\nexport LC_ALL=C\ntmpfile=`mktemp`\nnm -D $1 -p | sed -n '/ [TBD] /{s/.* [TBD] //;p;}' | sort > $tmpfile\nif cmp test/symvers.txt $tmpfile; then\n    echo PASS: exported symbols as expected\n    rv=0\nelse\n    echo FAIL: exported symbol mismatch\n    diff -c1 test/symvers.txt $tmpfile || true\n    rv=1\nfi\nrm $tmpfile\nexit $rv\n"
  },
  {
    "path": "test/common/ChangeLog",
    "content": "Wed Aug 25 19:27:26 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* child.c (reset_socket): New function.\n\nMon Jul  5 18:38:08 2004  Joe Orton  <joe@manyfish.co.uk>\n\n\t* tests.c (main): Print 'xfail' for expected failures.\n\nTue Oct  7 21:19:56 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* child.c (close_socket): New function.\n\t(server_child, spawn_server_repeat): Use it.\n\nFri Jul 25 12:13:59 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\tAdd support for test type which is expected to fail\n\tmemory leak checks.\n\t\n\t* tests.h (T_XLEAKY, T_EXPECT_LEAKS): New defines.\n\n\t* test.c (main) [NEON_MEMLEAK]: If T_EXPECT_LEAKS is set, fail if\n\tthe test did not leak memory.\n\nWed Jun 18 20:10:45 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* child.c (server_child, spawn_server_repeat): Adapt for new\n\tsocket API.\n\nSun Mar  9 17:52:11 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* test.h (T_EXPECT_FAIL): New constant.\n\t(T_XFAIL): New test function wrapper.\n\t\n\t* tests.c (main): Handle expected failures.\n\nSat Mar  1 21:04:35 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\tExtend the ne_test structure with a 'flags' field which can\n\toptionally request leak checking at run-time.\n\t\n\t* tests.h (ne_test): Add 'flags' field.\n\t(T_CHECK_LEAKS): New flag.\n\t(T): Use T_CHECK_LEAKS flag by default.\n\t(T_LEAKY): Like T, but with no flags set.\n\n\t* tests.c (main) [NEON_MEMLEAK]: If leak checking is requested,\n\tif a test passes, but leaks memory, fail the test.\n\nWed Feb 26 21:52:15 2003  Joe Orton  <joe@manyfish.co.uk>\n\n\t* tests.c (main): Test the \"disable debugging\" mode of\n\tne_debug_init, NE_DBG_FLUSH, and a ne_debug() with no output.\n\nFri Aug 23 22:54:35 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* tests.c (main): Call ne_sock_init after ne_debug_init, so that\n\tdebugging messages are caught from ne_sock_init.  Print a warning\n\tmessage if ne_sock_init fails.\n\nWed Aug 21 13:29:20 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* tests.h (ONCMP): New macro.\n\nMon Aug 19 16:53:20 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* child.c (lookup_localhost): Just use inet_addr to resolve\n\t127.0.0.1.\n\nSun Aug 18 13:50:30 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* tests.c (TEST_DEBUG): Add NE_DBG_SSL.\n\nSat Aug 10 10:19:18 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* child.c (server_send): Fix declaration.\n\t(discard_body): Use NE_FMT_SSIZE_T for print ssize_t's.\n\nSat Jul  6 08:42:37 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* child.c (discard_body): New function.\n\nSun Jun 30 10:26:33 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* child.c (server_send): New function.\n\t(discard_request): Fail with appropriate error.\n\nSun Jun 30 09:03:51 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* tests.c (main): Reap server after each test has run.\n\nSun Jun 30 09:00:43 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* child.c (reap_server): Set `child' to 0 so child can't be reaped\n\ttwice.\n\nSun Jun 23 12:09:09 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* child.c (serve_file): Use large buffer when sending in chunked\n\tmode to support large chunk sizes.\n\nSun Jun 23 09:35:09 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* child.c (serve_file): Use NE_FMT_OFF_T and NE_FMT_SSIZE_T.\n\nThu May 30 21:57:39 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* child.c (minisleep): Export function.\n\nSun May 19 18:23:19 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* child.c, tests.c: s/sock_/ne_sock_/, s/SOCK_/NE_SOCK_/ for\n\tsocket layer API change.\n\n\t* child.h (SEND_STRING): New macro.\n\nSun May 19 08:57:21 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* child.c (lookup_hostname): Conditionally use hstrerror().\n\nMon Feb 25 20:54:56 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* tests.c (t_context): Use ne_vsnprintf.\n\nMon Feb 11 21:52:23 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* child.c (lookup_hostname): New function.\n\t(server_child, do_listen): Pass around struct in_addr argument.\n\t(spawn_server_addr): Renamed from spawn_server, take bind_local\n\tflag to use localhost or \"real\" hostname to bind to.\n\t(spawn_server): New function, use spawn_server\n\nMon Feb 11 20:51:27 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* child.c (minisleep) [HAVE_USLEEP]: Use nice short usleep()\n\trather than boring long sleep().\n\nSat Feb  2 14:15:25 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* child.c (spawn_server_repeat): Exit child process (with failure)\n\tif the server callback fails.\n\nFri Jan  4 22:06:17 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* tests.h: Add SKIPREST result value.\n\t\n\t* tests.c (TEST_DEBUG): Add NE_DBG_LOCKS.  (main): Support\n\tSKIPREST.\n\nTue Jan  1 20:36:58 2002  Joe Orton  <joe@manyfish.co.uk>\n\n\t* tests.h: Make test_suite symbol have external linkage.\n\nSat Nov 10 22:28:55 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* tests.c, test.h: Export name of test suite.\n\nSun Nov  4 13:56:42 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* child.c (discard_request): Support retrieving arbitrary header\n\tvalues from request via want_request, got_request globals.\n\nWed Oct 24 21:41:39 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* tests.h (ONV): New macro.  (ON, ONN): Redefine in terms of ONV.\n\nWed Oct 24 20:44:59 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* tests.c (main, t_warning, segv): Use colours when stdout is a\n\tterminal device.\n\nWed Oct 24 20:36:38 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* tests.c (t_context, t_warning): Renamed from i_am, warning.\n\t(t_context): Take printf varargs. \n\n\t* tests.h (ONN, ON): Update, simplify.\n\n\t* child.c: Update.\n\nTue Oct 23 22:15:17 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* tests.c (main): Vertically align results after warnings.\n\nTue Oct  2 23:36:44 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* child.c (do_listen): Refactored from server_socket, only does\n\tbind/listen.  (spawn_server): Moved awaken/accept calls here.\n\t(spawn_server_repeat, dead_server): New functions.\n\nSun Sep 30 10:14:35 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* tests.h: Use a function/name structure for tests, add 'T' macro\n\tfor easily writing initializers.  Rename 'name' global variable to\n\t'test_context' to avoid parameter name collisions.\n\n\t* child.c (spawn_server): Update accordingly.\n\n\t* tests.c (i_am): Update accordingly.  (main): Update; prettify\n\toutput using new 'name' from test structure. Cope better when all\n\ttests in a suite are skipped.\n\nSat Sep 29 11:04:40 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* child.c (serve_file): If 'chunks' is set in argument object,\n\tthen deliver the file as a series of chunks.\n\nThu Sep 27 20:28:45 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* child.c (serve_file): New function.\n\nThu Sep 27 20:28:41 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* child.c (discard_request): Reset clength.\n\nMon Aug 27 00:31:09 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* tests.c (test_num): Expose test counter.  (segv): Handle\n\tsegfault nicely.\n\nMon Aug 27 00:30:20 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* child.c (discard_request): New function, from request.c in\n\tneon/test.\n\nWed Aug  8 22:09:21 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* tests.c, test.h: Only define test_argc/argv once.\n\nMon Jul 16 16:30:28 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* tests.c (warning): Take printf-style arguments list.\n\nMon Jul 16 16:16:08 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* tests.c (main): Cope with skipped tests properly.\n\nMon Jul 16 16:00:59 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* tests.c (warning): New function.  (main): Cope with warnings.\n\nSun Jul  8 16:09:33 2001  Joe Orton  <joe@manyfish.co.uk>\n\n\t* tests.c (main): Export argc/argv as test_argc, test_argv.\n\n\n"
  },
  {
    "path": "test/common/README",
    "content": "\nSimple test framework for neon; licensed under the GNU GPL.\n\nCopyright (C) 2001-2002 Joe Orton\n"
  },
  {
    "path": "test/common/child.c",
    "content": "/* \n   Framework for testing with a server process\n   Copyright (C) 2001-2024, Joe Orton <joe@manyfish.co.uk>\n\n   This program is free software; you can redistribute it and/or modify\n   it under the terms of the GNU General Public License as published by\n   the Free Software Foundation; either version 2 of the License, or\n   (at your option) any later version.\n  \n   This program is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU General Public License for more details.\n  \n   You should have received a copy of the GNU General Public License\n   along with this program; if not, write to the Free Software\n   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\n*/\n\n#include \"config.h\"\n\n#include <sys/types.h>\n\n#include <sys/wait.h>\n#include <sys/socket.h>\n#include <netinet/in.h>\n#include <arpa/inet.h>\n\n#include <sys/stat.h>\n\n#ifdef HAVE_ERRNO_H\n#include <errno.h>\n#endif\n#ifdef HAVE_UNISTD_H\n#include <unistd.h>\n#endif\n#ifdef HAVE_STDLIB_H\n#include <stdlib.h>\n#endif\n#ifdef HAVE_STRING_H\n#include <string.h>\n#endif\n\n#include <fcntl.h>\n#include <netdb.h>\n#include <signal.h>\n\n#include \"ne_socket.h\"\n#include \"ne_utils.h\"\n#include \"ne_string.h\"\n\n#include \"tests.h\"\n#include \"child.h\"\n\n#ifndef NEON_NO_TEST_CHILD\n\n#ifndef NI_MAXHOST\n#define NI_MAXHOST 1025\n#endif\n\nstatic pid_t child = 0;\n\nunsigned long clength;\n\nstruct server_addr {\n    int family;\n    union {\n\tstruct sockaddr_in in;\n\tstruct sockaddr_in6 in6;\n    } sockaddr;\n    char name[NI_MAXHOST];\n};\n\nstruct server_addr lh;\n\nconst char *want_header = NULL;\ngot_header_fn got_header = NULL;\n\n/* If we have pipe(), then use a pipe between the parent and child to\n * know when the child is ready to accept incoming connections.\n * Otherwise use boring sleep()s trying to avoid the race condition\n * between listen() and connect() in the two processes. */\n#ifdef HAVE_PIPE\n#define USE_PIPE 1\n#endif\n\nint lookup_localhost(void)\n{\n#ifdef USE_GETADDRINFO\n    struct addrinfo hints = {}, *results, *rp;\n#endif\n\n    if (lh.family != AF_UNSPEC)\n\treturn OK;\n\n#ifdef USE_GETADDRINFO\n\n#ifdef USE_GAI_ADDRCONFIG\n    hints.ai_flags = AI_ADDRCONFIG;\n#endif\n    hints.ai_family = AF_UNSPEC;\n    hints.ai_socktype = SOCK_STREAM;\n\n    if (getaddrinfo(\"localhost\", NULL, &hints, &results) != 0)\n\tgoto err_use_ipv4;\n\n    for (rp = results; rp != NULL; rp = rp->ai_next) {\n\tint sock, rv;\n\n\tif (rp->ai_family != AF_INET &&\n\t    rp->ai_family != AF_INET6)\n\t    continue;\n\n\tsock = socket(rp->ai_family, rp->ai_socktype, 0);\n\tif (sock < 0)\n\t    continue;\n\trv = bind(sock, rp->ai_addr, rp->ai_addrlen);\n\tclose(sock);\n\tif (rv < 0)\n\t    continue;\n\n\tif (getnameinfo(rp->ai_addr, rp->ai_addrlen,\n\t\t\tlh.name, sizeof lh.name, NULL, 0,\n\t\t\tNI_NUMERICHOST))\n\t    continue;\n\n\tlh.family = rp->ai_family;\n\tmemcpy(&lh.sockaddr, rp->ai_addr, rp->ai_addrlen);\n\tbreak;\n    }\n\n    freeaddrinfo(results);\n\nerr_use_ipv4:\n\n#endif\n\n    if (lh.family == AF_UNSPEC) {\n\t/* this will break if a system is set up so that `localhost' does\n\t * not resolve to 127.0.0.1, but... */\n\tlh.family = AF_INET;\n\tstrcpy(lh.name, \"127.0.0.1\");\n\tlh.sockaddr.in.sin_family = lh.family;\n\tlh.sockaddr.in.sin_addr.s_addr = inet_addr(lh.name);\n    }\n\n    return OK;\n}\n\nint\nget_lh_family(void)\n{\n    if (lh.family == AF_UNSPEC)\n        lookup_localhost();\n\n    return lh.family;\n}\n\nconst char *\nget_lh_addr(void)\n{\n    if (lh.family == AF_UNSPEC)\n        lookup_localhost();\n\n    return lh.name;\n}\n\nne_inet_addr *\nget_lh_inet_addr(void)\n{\n    ne_iaddr_type type;\n    unsigned char *raw;\n\n    if (lh.family == AF_UNSPEC)\n        lookup_localhost();\n\n    if (lh.family == AF_INET) {\n\ttype = ne_iaddr_ipv4;\n\traw = (unsigned char *) &lh.sockaddr.in.sin_addr.s_addr;\n    } else {\n\ttype = ne_iaddr_ipv6;\n\traw = lh.sockaddr.in6.sin6_addr.s6_addr;\n    }\n\n    return ne_iaddr_make(type, raw);\n}\n\nstatic int do_listen(int port)\n{\n    int ls = socket(lh.family, SOCK_STREAM, 0);\n    struct sockaddr *saddr;\n    socklen_t saddrlen;\n    int val = 1;\n\n    setsockopt(ls, SOL_SOCKET, SO_REUSEADDR, (void *)&val, sizeof(int));\n\n    if (lh.family == AF_INET) {\n\tlh.sockaddr.in.sin_port = htons(port);\n\tsaddr = (struct sockaddr *) &lh.sockaddr.in;\n\tsaddrlen = sizeof lh.sockaddr.in;\n    } else {\n\tlh.sockaddr.in6.sin6_port = htons(port);\n\tsaddr = (struct sockaddr *) &lh.sockaddr.in6;\n\tsaddrlen = sizeof lh.sockaddr.in6;\n    }\n\n    if (bind(ls, saddr, saddrlen)) {\n\tprintf(\"bind failed: %s\\n\", strerror(errno));\n\treturn -1;\n    }\n    if (listen(ls, 5)) {\n\tprintf(\"listen failed: %s\\n\", strerror(errno));\n\treturn -1;\n    }\n\n    return ls;\n}\n\nvoid minisleep(void)\n{\n#ifdef HAVE_USLEEP\n    usleep(500);\n#else\n    sleep(1);\n#endif\n}\n\nint reset_socket(ne_socket *sock)\n{\n#ifdef SO_LINGER\n    /* Stevens' magic trick to send an RST on close(). */\n    struct linger l = {1, 0};\n    return setsockopt(ne_sock_fd(sock), SOL_SOCKET, SO_LINGER, &l, sizeof l);\n#else\n    return 1;\n#endif\n}\n\n/* close 'sock', performing lingering close to avoid premature RST. */\nstatic int close_socket(ne_socket *sock)\n{\n    int ret;\n    char buf[20];\n\n    ret = ne_sock_shutdown(sock, NE_SOCK_SEND);\n    if (ret == 0) {\n\tNE_DEBUG(NE_DBG_SOCKET, \"ssl: Socket cleanly closed.\\n\");\n    }\n    else {\n\tNE_DEBUG(NE_DBG_SOCKET, \"sock: Socket closed uncleanly: %s\\n\",\n\t\t ne_sock_error(sock));\n    }\n\n    NE_DEBUG(NE_DBG_SSL, \"sock: Lingering close...\\n\");\n    ne_sock_read_timeout(sock, 5);\n    while (ne_sock_read(sock, buf, sizeof buf) > 0);\n\n    NE_DEBUG(NE_DBG_SSL, \"sock: Closing socket.\\n\");\n    ret = ne_sock_close(sock);\n    NE_DEBUG(NE_DBG_SSL, \"sock: Socket closed (%d).\\n\", ret);\n    return ret;\n}\n\nint new_spawn_server(int count, server_fn fn, void *userdata,\n                     unsigned int *port)\n{\n    ne_inet_addr *addr = NULL;\n    int ret;\n\n    ret = new_spawn_server2(count, fn, userdata, &addr, port);\n    if (addr)\n        ne_iaddr_free(addr);\n\n    return ret;\n}\n\nint new_spawn_server2(int count, server_fn fn, void *userdata,\n                      ne_inet_addr **addr, unsigned int *port)\n{\n    union {\n\tstruct sockaddr_in  in;\n\tstruct sockaddr_in6 in6;\n    } sa;\n    socklen_t salen = sizeof sa;\n    int ls;\n\n    if (lh.family == AF_UNSPEC)\n        lookup_localhost();\n\n    ls = do_listen(0);\n    ONN(\"could not bind/listen fd for server\", ls < 0);\n\n    ONV(getsockname(ls, (struct sockaddr *) &sa, &salen) != 0,\n        (\"could not get socket name for listening fd: %s\",\n         strerror(errno)));\n\n    if (salen == sizeof sa.in) {\n\t*port = ntohs(sa.in.sin_port);\n\t*addr = ne_iaddr_make(ne_iaddr_ipv4,\n\t\t\t      (unsigned char *) &sa.in.sin_addr.s_addr);\n    } else {\n\t*port = ntohs(sa.in6.sin6_port);\n\t*addr = ne_iaddr_make(ne_iaddr_ipv6, sa.in6.sin6_addr.s6_addr);\n    }\n\n    NE_DEBUG(NE_DBG_SOCKET, \"child: using port %u\\n\", *port);\n\n    NE_DEBUG(NE_DBG_SOCKET, \"child: forking now...\\n\");\n\n    child = fork();\n    ONN(\"failed to fork server\", child == -1);\n\n    if (child == 0) {\n        int ret, iter = 1;\n        \n        in_child();\n\n        NE_DEBUG(NE_DBG_SOCKET, \">>> child spawned, port %u, %d iterations.\\n\",\n                 *port, count);\n\n        do {\n            ne_socket *sock = ne_sock_create();\n            char errbuf[256];            \n            int cret;\n\n            NE_DEBUG(NE_DBG_HTTP, \"child: iteration #%d (of %d), \"\n                     \"awaiting connection...\\n\", iter, count);\n\n            if (ne_sock_accept(sock, ls)) {\n                t_context(\"Server child could not accept connection: %s\", \n                          ne_sock_error(sock));\n                exit(FAIL);\n            }\n\n            NE_DEBUG(NE_DBG_HTTP, \"child: got connection, invoking server\\n\");\n            if (iter == count) {\n                close(ls);\n                NE_DEBUG(NE_DBG_HTTP, \"child: closed listening socket.\\n\");\n            }\n\n            ret = fn(sock, userdata);\n            NE_DEBUG(NE_DBG_HTTP, \"child: iteration #%d returns %d\\n\",\n                     iter, ret);\n\n\t    cret = close_socket(sock);\n\t    NE_DEBUG(NE_DBG_HTTP, \"child: closed connection, %d: %s.\\n\", cret,\n                     cret ? ne_strerror(cret, errbuf, sizeof errbuf) \n                     : \"no error\");\n\n        } while (ret == 0 && ++iter <= count);\n\n        NE_DEBUG(NE_DBG_HTTP, \"child: terminating with %d\\n\", ret);\n        exit(ret);\n    }\n\n    close(ls);\n\n    return OK;\n}\n\nint dead_server(void)\n{\n    int status;\n\n    if (waitpid(child, &status, WNOHANG)) {\n\t/* child quit already! */\n\treturn FAIL;\n    }\n\n    NE_DEBUG(NE_DBG_HTTP, \"child has not quit.\\n\");\n\n    return OK;\n}\n\nint destroy_and_wait(ne_session *sess)\n{\n    ne_session_destroy(sess);\n    return await_server();\n}\n\nint await_server(void)\n{\n    int status, code;\n\n    (void) wait(&status);\n    \n    /* so that we aren't reaped by mistake. */\n    child = 0;\n\n    if (WIFEXITED(status)) {\n        code = WEXITSTATUS(status);\n        \n        ONV(code,\n            (\"server process terminated abnormally: %s (%d)\",\n             code == FAIL ? \"FAIL\" : \"error\", code));\n    }\n    else {\n        ONV(WIFSIGNALED(status),\n            (\"server process terminated by signal %d\", WTERMSIG(status)));\n    }\n\n    return OK;\n}\n\nint reap_server(void)\n{\n    int status;\n    \n    if (child != 0) {\n\t(void) kill(child, SIGTERM);\n\tminisleep();\n\t(void) wait(&status);\n\tchild = 0;\n    }\n\n    return OK;\n}\n\nssize_t server_send(ne_socket *sock, const char *str, size_t len)\n{\n    NE_DEBUG(NE_DBG_HTTP, \"Sending: %.*s\\n\", (int)len, str);\n    return ne_sock_fullwrite(sock, str, len);\n}\n\nint discard_request(ne_socket *sock)\n{\n    char buffer[1024];\n    size_t offset = want_header?strlen(want_header):0;\n\n    clength = 0;\n\n    NE_DEBUG(NE_DBG_HTTP, \"Discarding request...\\n\");\n    do {\n\tONV(ne_sock_readline(sock, buffer, 1024) < 0,\n\t    (\"error reading line: %s\", ne_sock_error(sock)));\n\tNE_DEBUG(NE_DBG_HTTP, \"[req] %s\", buffer);\n\tif (strncasecmp(buffer, \"content-length: \", 16) == 0) {\n            char *ptr = NULL;\n            errno = 0;\n            clength = strtoul(buffer + 16, &ptr, 10);\n            ONV(errno || *ptr != '\\r',\n                (\"invalid Content-Length request header: %s\", buffer));\n\t}\n\tif (got_header != NULL && want_header != NULL && \n\t    strncasecmp(buffer, want_header, offset) == 0 &&\n\t    buffer[offset] == ':') {\n\t    char *value = buffer + offset + 1;\n\t    if (*value == ' ') value++;\n\t    got_header(ne_shave(value, \"\\r\\n\"));\n\t}\n    } while (strcmp(buffer, \"\\r\\n\") != 0);\n    \n    return OK;\n}\n\nint error_response(ne_socket *sock, int ret)\n{\n    char resp[1024];\n\n    ne_snprintf(resp, sizeof resp,\n                \"HTTP/1.1 500 Server Test Failed\\r\\n\"\n                \"X-Neon-Context: %s\\r\\n\"\n                \"Content-Length: 0\\r\\n\"\n                \"Connection: close\\r\\n\"\n                \"\\r\\n\",\n                test_context);\n    SEND_STRING(sock, resp);\n\n    return ret;\n}\n\n\nint discard_body(ne_socket *sock)\n{\n    while (clength > 0) {\n\tchar buf[BUFSIZ];\n\tsize_t bytes = clength;\n\tssize_t ret;\n\tif (bytes > sizeof(buf)) bytes = sizeof(buf);\n\tNE_DEBUG(NE_DBG_HTTP, \"Discarding %\" NE_FMT_SIZE_T \" bytes.\\n\",\n\t\t bytes);\n\tret = ne_sock_read(sock, buf, bytes);\n\tONV(ret < 0, (\"socket read failed (%\" NE_FMT_SSIZE_T \"): %s\", \n\t\t      ret, ne_sock_error(sock)));\n\tclength -= ret;\n\tNE_DEBUG(NE_DBG_HTTP, \"Got %\" NE_FMT_SSIZE_T \" bytes.\\n\", ret);\n    }\n    NE_DEBUG(NE_DBG_HTTP, \"Discard successful.\\n\");\n    return OK;\n}\n\nint serve_file(ne_socket *sock, void *ud)\n{\n    char buffer[BUFSIZ];\n    struct stat st;\n    struct serve_file_args *args = ud;\n    ssize_t ret;\n    int fd;\n\n    CALL(discard_request(sock));\n\n    ne_sock_fullread(sock, buffer, clength);\n\n    fd = open(args->fname, O_RDONLY);\n    if (fd < 0) {\n\tSEND_STRING(sock, \n\t\t    \"HTTP/1.0 404 File Not Found\\r\\n\"\n\t\t    \"Content-Length: 0\\r\\n\\r\\n\");\n\treturn 0;\n    }\n\n    ONN(\"fstat fd\", fstat(fd, &st));\n\n    SEND_STRING(sock, \"HTTP/1.0 200 OK\\r\\n\");\n    if (args->chunks) {\n\tsprintf(buffer, \"Transfer-Encoding: chunked\\r\\n\");\n    } else {\n\tsprintf(buffer, \"Content-Length: %\" NE_FMT_OFF_T \"\\r\\n\", \n\t\tst.st_size);\n    } \n    \n    if (args->headers) {\n\tstrcat(buffer, args->headers);\n    }\n\n    strcat(buffer, \"\\r\\n\");\n\n    SEND_STRING(sock, buffer);\n\n    NE_DEBUG(NE_DBG_HTTP, \"Serving %s (%\" NE_FMT_OFF_T \" bytes).\\n\",\n\t     args->fname, st.st_size);\n\n    if (args->chunks) {\n\tchar buf[1024];\n\t\n\twhile ((ret = read(fd, &buf, args->chunks)) > 0) {\n\t    /* this is a small integer, cast it explicitly to avoid\n\t     * warnings with printing an ssize_t. */\n\t    sprintf(buffer, \"%x\\r\\n\", (unsigned int)ret);\n\t    SEND_STRING(sock, buffer);\n\t    ONN(\"writing body\", ne_sock_fullwrite(sock, buf, ret));\n\t    SEND_STRING(sock, \"\\r\\n\");\n\t}\n\t\n\tSEND_STRING(sock, \"0\\r\\n\\r\\n\");\n\t\n    } else {\n\twhile ((ret = read(fd, buffer, BUFSIZ)) > 0) {\n\t    ONN(\"writing body\", ne_sock_fullwrite(sock, buffer, ret));\n\t}\n    }\n\n    ONN(\"error reading from file\", ret < 0);\n\n    (void) close(fd);\n\n    return OK;\n}\n\n#endif /* NEON_NO_TEST_CHILD */\n"
  },
  {
    "path": "test/common/child.h",
    "content": "/* \n   Framework for testing with a server process\n   Copyright (C) 2001-2004, 2009, Joe Orton <joe@manyfish.co.uk>\n\n   This program is free software; you can redistribute it and/or modify\n   it under the terms of the GNU General Public License as published by\n   the Free Software Foundation; either version 2 of the License, or\n   (at your option) any later version.\n  \n   This program is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU General Public License for more details.\n  \n   You should have received a copy of the GNU General Public License\n   along with this program; if not, write to the Free Software\n   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\n*/\n\n#ifndef CHILD_H\n#define CHILD_H 1\n\n#include \"config.h\"\n\n#ifdef HAVE_STRING_H\n#include <string.h> /* for strlen() */\n#endif\n\n#include \"ne_socket.h\"\n#include \"ne_session.h\"\n\n/* Test which does DNS lookup on \"localhost\": this must be the first\n * named test. */\nint lookup_localhost(void);\n\nint get_lh_family(void);\nconst char *get_lh_addr(void);\nne_inet_addr *get_lh_inet_addr(void);\n\n/* Callback for spawn_server. */\ntypedef int (*server_fn)(ne_socket *sock, void *userdata);\n\n/* Forks a server child process running 'fn(userdata)' on an\n * unspecified port.  Sets test suite error on failure; on success,\n * sets *port to bound port number. */\nint new_spawn_server(int count, server_fn fn, void *userdata, \n                     unsigned int *port);\n\n/* As per new_spawn_server, but also returns the bound address as *addr. */\nint new_spawn_server2(int count, server_fn fn, void *userdata,\n                      ne_inet_addr **addr, unsigned int *port);\n\n/* Blocks until child process exits, and gives return code of 'fn'. */\nint await_server(void);\n\n/* Destroys session 'sess' and then is equivalent to await_server. */\nint destroy_and_wait(ne_session *sess);\n\n/* Kills child process. */\nint reap_server(void);\n\n/* Returns non-zero if server process has already died. */\nint dead_server(void);\n\n/* If discard_request comes across a header called 'want_header', it\n * will call got_header passing the header field value. */\nextern const char *want_header;\ntypedef void (*got_header_fn)(char *value);\nextern got_header_fn got_header;\n\n/* Send string to child; ne_sock_fullwrite with debugging. */\nssize_t server_send(ne_socket *sock, const char *data, size_t len);\n\n/* Utility macro: send given string down socket. */\n#define SEND_STRING(sock, str) server_send((sock), (str), strlen((str)))\n\n/* If test result 'err' is not OK, return an HTTP 500 error response\n * including the test context in a response header. */\n#define ONERR(sock, err) do { int ret_ = (err); if (ret_) return error_response(sock, ret_); } while (0)\n\n/* Send an HTTP error response including the test context in a\n * response header. */\nint error_response(ne_socket *sock, int ret);\n\n/* Tries to ensure that the socket will be closed using RST rather\n * than FIN. */\nint reset_socket(ne_socket *sock);\n\n/* Utility function: discard request.  Sets context on error. */\nint discard_request(ne_socket *sock);\n\n/* Utility function: discard request body. Sets context on error. */\nint discard_body(ne_socket *sock);\n\nstruct serve_file_args {\n    const char *fname;\n    const char *headers;\n    int chunks; \n};\n\n/* Utility function: callback for spawn_server: pass pointer to\n * serve_file_args as userdata, and args->fname is served as a 200\n * request. If args->headers is non-NULL, it must be a set of\n * CRLF-terminated lines which is added in to the response headers.\n * If args->chunks is non-zero, the file is delivered using chunks of\n * that size. */\nint serve_file(ne_socket *sock, void *ud);\n\n/* set to value of C-L header by discard_request. */\nextern unsigned long clength;\n\n/* Sleep for a short time. */\nvoid minisleep(void);\n\n#endif /* CHILD_H */\n"
  },
  {
    "path": "test/common/run.sh",
    "content": "#!/bin/sh\n\nrm -f debug.log\nrm -f child.log\n\n# for shared builds.\nLD_LIBRARY_PATH=../src/.libs:$LD_LIBRARY_PATH\nexport LD_LIBRARY_PATH\n\nfor f in $*; do\n    if ./$f; then\n\t:\n    else\n\techo FAILURE\n\texit 1\n    fi\ndone\n\nexit 0\n"
  },
  {
    "path": "test/common/tests.c",
    "content": "/* \n   Stupidly simple test framework\n   Copyright (C) 2001-2009, Joe Orton <joe@manyfish.co.uk>\n\n   This program is free software; you can redistribute it and/or modify\n   it under the terms of the GNU General Public License as published by\n   the Free Software Foundation; either version 2 of the License, or\n   (at your option) any later version.\n  \n   This program is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU General Public License for more details.\n  \n   You should have received a copy of the GNU General Public License\n   along with this program; if not, write to the Free Software\n   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\n*/\n\n#include \"config.h\"\n\n#include <sys/types.h>\n\n#include <stdio.h>\n#ifdef HAVE_SIGNAL_H\n#include <signal.h>\n#endif\n#ifdef HAVE_UNISTD_H\n#include <unistd.h>\n#endif\n#ifdef HAVE_STRING_H\n#include <string.h>\n#endif\n#ifdef HAVE_STDLIB_H\n#include <stdlib.h>\n#endif\n#ifdef HAVE_ERRNO_H\n#include <errno.h>\n#endif\n#ifdef HAVE_LOCALE_H\n#include <locale.h>\n#endif\n\n#include \"ne_string.h\"\n#include \"ne_utils.h\"\n#include \"ne_socket.h\"\n#include \"ne_i18n.h\"\n\n#include \"tests.h\"\n#include \"child.h\"\n\nchar test_context[BUFSIZ];\nint have_context = 0;\n\nstatic FILE *child_debug, *debug;\n\nchar **test_argv;\nint test_argc;\n\nconst char *test_suite;\nint test_num;\n\nstatic int quiet, count;\n\n/* statistics for all tests so far */\nstatic int passes = 0, fails = 0, skipped = 0, warnings = 0;\n\n/* per-test globals: */\nstatic int warned, aborted = 0;\nstatic const char *test_name; /* current test name */\n\nstatic int use_colour = 0, tty_output = 0;\n\nstatic int flag_child;\n\nstatic void print_prefix(int n);\n\n/* resource for ANSI escape codes:\n * http://www.isthe.com/chongo/tech/comp/ansi_escapes.html */\n#define COL(x) do { if (use_colour) printf(\"\\033[\" x \"m\"); } while (0)\n\n#define NOCOL COL(\"00\")\n\nvoid t_context(const char *context, ...)\n{\n    va_list ap;\n    va_start(ap, context);\n    ne_vsnprintf(test_context, BUFSIZ, context, ap);\n    va_end(ap);\n    if (flag_child) {\n        NE_DEBUG(NE_DBG_HTTP, \"context: %s\\n\", test_context);\n    }\n    have_context = 1;\n}\n\nvoid t_warning(const char *str, ...)\n{\n    va_list ap;\n    if (warned) print_prefix(test_num);\n    COL(\"43;01\"); printf(\"WARNING:\"); NOCOL;\n    putchar(' ');\n    va_start(ap, str);\n    vprintf(str, ap);\n    va_end(ap);\n    warnings++;\n    warned++;\n    putchar('\\n');\n}    \n\n#define TEST_DEBUG \\\n(NE_DBG_HTTP | NE_DBG_SOCKET | NE_DBG_HTTPBODY | NE_DBG_HTTPAUTH | \\\n NE_DBG_LOCKS | NE_DBG_XMLPARSE | NE_DBG_XML | NE_DBG_SSL | \\\n NE_DBG_HTTPPLAIN)\n\n#define W(m) do { if (write(STDOUT_FILENO, m, strlen(m)) < 0) _exit(99); } while(0)\n\n#define W_RED(m) do { if (use_colour) W(\"\\033[41;37;01m\"); \\\nW(m); if (use_colour) W(\"\\033[00m\\n\"); } while (0);\n\n#ifndef NEON_NO_TEST_CHILD\n\n/* Signal handler for child processes. */\nstatic void child_segv(int signo)\n{\n    signal(SIGSEGV, SIG_DFL); \n    signal(SIGABRT, SIG_DFL);\n    W_RED(\"Fatal signal in child!\");\n    kill(getpid(), SIGSEGV);\n    minisleep();\n}\n\n/* Signal handler for parent process. */\nstatic void parent_segv(int signo)\n{\n    signal(SIGSEGV, SIG_DFL);\n    signal(SIGABRT, SIG_DFL);\n    if (signo == SIGSEGV) {\n        W_RED(\"FAILED - Segmentation fault--\\n\");\n    }\n    else if (signo == SIGABRT) {\n        W_RED(\"ABORTED\\n\");\n    }\n    else {\n        W_RED(\"-- Unexpected signal! --\\n\");\n    }\n    reap_server();\n    kill(getpid(), signo);\n    minisleep();\n}\n\nvoid in_child(void)\n{\n    if (child_debug) {\n        ne_debug_init(child_debug, TEST_DEBUG);\n        NE_DEBUG(TEST_DEBUG, \"**** Child forked for test %s ****\\n\", test_name);\n        signal(SIGSEGV, child_segv);\n        signal(SIGABRT, child_segv);\n        flag_child = 1;\n    }\n}\n#endif\n\nstatic const char dots[] = \"......................\";\n\nstatic void print_prefix(int n)\n{\n    if (quiet) {\n        printf(\"\\r%s%.*s %2u/%2u \", test_suite, \n               (int) (strlen(dots) - strlen(test_suite)), dots,\n               n + 1, count);\n    }\n    else {\n        if (warned) {\n\t    printf(\"    %s \", dots);\n        }\n        else {\n            printf(\"\\r%2d. %s%.*s \", n, test_name, \n               (int) (strlen(dots) - strlen(test_name)), dots);\n        }\n    }\n    fflush(stdout);\n}\n\n\nint main(int argc, char *argv[])\n{\n    int n;\n    char *tmp;\n    \n    /* get basename(argv[0]) */\n    test_suite = strrchr(argv[0], '/');\n    if (test_suite == NULL) {\n\ttest_suite = argv[0];\n    } else {\n\ttest_suite++;\n    }\n\n    if (strncmp(test_suite, \"lt-\", 3) == 0)\n        test_suite += 3;\n\n#ifdef HAVE_SETLOCALE\n    setlocale(LC_MESSAGES, \"\");\n#endif\n\n    ne_i18n_init(NULL);\n\n#if defined(HAVE_ISATTY) && defined(STDOUT_FILENO)\n    tty_output = isatty(STDOUT_FILENO);\n#endif\n\n    if ((tmp = getenv(\"TEST_COLOUR\")) != NULL)\n        use_colour = strcmp(tmp, \"1\") == 0;\n    else\n        use_colour = tty_output;\n\n    test_argc = argc;\n    test_argv = argv;\n\n    if ((tmp = getenv(\"TEST_NODEBUG\")) == NULL) {\n        debug = fopen(\"debug.log\", \"a\");\n        if (debug == NULL) {\n            fprintf(stderr, \"%s: Could not open debug.log: %s\\n\", test_suite,\n                    strerror(errno));\n            return -1;\n        }\n        child_debug = fopen(\"child.log\", \"a\");\n        if (child_debug == NULL) {\n            fprintf(stderr, \"%s: Could not open child.log: %s\\n\", test_suite,\n                    strerror(errno));\n            fclose(debug);\n            return -1;\n        }\n    }\n\n    if (tests[0].fn == NULL) {\n\tprintf(\"-> no tests found in `%s'\\n\", test_suite);\n\treturn -1;\n    }\n\n#ifndef NEON_NO_TEST_CHILD\n    /* install special SEGV handler. */\n    signal(SIGSEGV, parent_segv);\n    signal(SIGABRT, parent_segv);\n#endif\n\n    /* test the \"no-debugging\" mode of ne_debug. */\n    ne_debug_init(NULL, 0);\n    NE_DEBUG(TEST_DEBUG, \"This message should go to /dev/null\");\n\n    if (debug) {\n        /* enable debugging for real. */\n        ne_debug_init(debug, TEST_DEBUG);\n        NE_DEBUG(TEST_DEBUG | NE_DBG_FLUSH, \"Version string: %s\\n\", \n                 ne_version_string());\n    }\n\n    /* another silly test. */\n    NE_DEBUG(0, \"This message should also go to /dev/null\");\n\n    if (ne_sock_init()) {\n\tCOL(\"43;01\"); printf(\"WARNING:\"); NOCOL;\n\tprintf(\" Socket library initialization failed.\\n\");\n    }\n\n#ifdef NEON_TEST_INIT\n    if (NEON_TEST_INIT(test_argc, (const char *const *)test_argv, &use_colour, &quiet)) {\n\tfprintf(stderr, \"%s: Failed parsing command-line.\\n\", test_suite);\n        return -1;\n    }\n#endif\n\n    if ((tmp = getenv(\"TEST_QUIET\")) != NULL) {\n        quiet = strcmp(tmp, \"1\") == 0;\n    }\n\n    if (!quiet)\n        printf(\"-> running `%s':\\n\", test_suite);\n    \n    for (count = 0; tests[count].fn; count++)\n        /* nullop */;\n\n    for (n = 0; !aborted && tests[n].fn != NULL; n++) {\n\tint result, is_xfail = 0;\n#ifdef NEON_MEMLEAK\n        size_t allocated = ne_alloc_used;\n        int is_xleaky = 0;\n#endif\n\n\ttest_name = tests[n].name;\n\n        print_prefix(n);\n\n\thave_context = 0;\n\ttest_num = n;\n\twarned = 0;\n\tfflush(stdout);\n\tNE_DEBUG(TEST_DEBUG, \"******* Running test %d: %s ********\\n\", \n\t\t n, test_name);\n\n\t/* run the test. */\n\tresult = tests[n].fn();\n\n#ifdef NEON_MEMLEAK\n        /* issue warnings for memory leaks, if requested */\n        if ((tests[n].flags & T_CHECK_LEAKS)\n            && (result == OK || result == SKIP) &&\n            ne_alloc_used > allocated) {\n            t_context(\"memory leak of %\" NE_FMT_SIZE_T \" bytes\",\n                      ne_alloc_used - allocated);\n            fprintf(debug, \"Blocks leaked: \");\n            ne_alloc_dump(debug);\n            result = FAIL;\n        } else if (tests[n].flags & T_EXPECT_LEAKS && result == OK &&\n                   ne_alloc_used == allocated) {\n            t_context(\"expected memory leak not detected\");\n            result = FAIL;\n        } else if (tests[n].flags & T_EXPECT_LEAKS && result == OK) {\n            fprintf(debug, \"Blocks leaked (expected): \");\n            ne_alloc_dump(debug);\n            is_xleaky = 1;\n        } \n#endif\n\n        if (tests[n].flags & T_EXPECT_FAIL) {\n            if (result == OK) {\n                t_context(\"test passed but expected failure\");\n                result = FAIL;\n            } else if (result == FAIL) {\n                result = OK;\n                is_xfail = 1;\n            }\n        }\n\n        print_prefix(n);\n\n\tswitch (result) {\n\tcase OK:\n\t    passes++;\n            if (is_xfail) {\n                COL(\"32;07\"); \n                printf(\"XFAIL\");\n            } else if (!quiet) {\n                COL(\"32\"); \n                printf(\"pass\"); \n            }\n            NOCOL;\n            if (quiet && is_xfail) {\n                printf(\" - %s\", test_name);\n                if (have_context) {\n                    printf(\" (%s)\", test_context);\n                }\n            }\n\t    if (warned && !quiet) {\n\t\tprintf(\" (with %d warning%s)\", warned, (warned > 1)?\"s\":\"\");\n\t    }\n#ifdef NEON_MEMLEAK\n            if (is_xleaky) {\n                if (quiet) {\n                    printf(\"expected leak - %s: %\" NE_FMT_SIZE_T \" bytes\",\n                           test_name, ne_alloc_used - allocated);\n                }\n                else {\n                    printf(\" (expected leak, %\" NE_FMT_SIZE_T \" bytes)\",\n                           ne_alloc_used - allocated);\n                }\n            }\n#endif\n\t    if (!quiet || is_xfail) putchar('\\n');\n\t    break;\n\tcase FAILHARD:\n\t    aborted = 1;\n\t    COL(\"41;37;01\"); printf(\"fatal error - \"); NOCOL;\n\t    /* fall-through */\n\tcase FAIL:\n\t    COL(\"41;37;01\"); printf(\"FAIL\"); NOCOL;\n            if (quiet) {\n                printf(\" - %s\", test_name);\n            }\n\t    if (have_context) {\n\t\tprintf(\" (%s)\", test_context);\n\t    }\n\t    putchar('\\n');\n\t    fails++;\n\t    break;\n\tcase SKIPREST:\n\t    aborted = 1;\n\t    /* fall-through */\n\tcase SKIP:\n\t    COL(\"44;37;01\"); printf(\"SKIPPED\"); NOCOL;\n            if (quiet) {\n                printf(\" - %s\", test_name);\n            }\n\t    if (have_context) {\n\t\tprintf(\" (%s)\", test_context);\n\t    }\n\t    putchar('\\n');\n\t    skipped++;\n\t    break;\n\tdefault:\n\t    COL(\"41;37;01\"); printf(\"OOPS\"); NOCOL;\n\t    printf(\" unexpected test result `%d'\\n\", result);\n\t    break;\n\t}\n\n#ifndef NEON_NO_TEST_CHILD\n\treap_server();\n#endif\n\n        if (quiet) {\n            print_prefix(n);\n        }\n    }\n\n    /* discount skipped tests */\n    if (skipped) {\n        if (!quiet) \n            printf(\"-> %d %s.\\n\", skipped,\n                   skipped == 1 ? \"test was skipped\" : \"tests were skipped\");\n\tn -= skipped;\n    }\n    /* print the summary. */\n    if (skipped && n == 0) {\n        if (quiet)\n            puts(\"(all skipped)\");\n        else\n            printf(\"<- all tests skipped for `%s'.\\n\", test_suite);\n    } else {\n        if (quiet) {\n            printf(\"\\r%s%.*s %2u/%2u \", test_suite, \n                   (int) (strlen(dots) - strlen(test_suite)), dots,\n                   passes, count);\n            if (fails == 0) {\n                COL(\"32\"); \n                printf(\"passed\");\n                NOCOL;\n                putchar(' ');\n            }\n            else {\n                printf(\"passed, %d failed \", fails);\n            }                       \n            if (skipped)\n                printf(\"(%d skipped) \", skipped);\n        }\n        else /* !quiet */\n            printf(\"<- summary for `%s': \"\n                   \"of %d tests run: %d passed, %d failed. %.1f%%\\n\",\n                   test_suite, n, passes, fails, 100*(float)passes/n);\n\tif (warnings) {\n\t    if (quiet) {\n                printf(\"(%d warning%s)\\n\", warnings, \n                       warnings > 1 ? \"s\" : \"\");\n            }\n            else {\n                printf(\"-> %d warning%s issued.\\n\", warnings, \n                       warnings==1?\" was\":\"s were\");\n            }\n        }\n        else if (quiet) {\n            putchar('\\n');\n        }\n    }\n\n    if (debug && fclose(debug)) {\n\tfprintf(stderr, \"Error closing debug.log: %s\\n\", strerror(errno));\n\tfails = 1;\n    }\n       \n    if (child_debug && fclose(child_debug)) {\n\tfprintf(stderr, \"Error closing child.log: %s\\n\", strerror(errno));\n\tfails = 1;\n    }\n\n    ne_sock_exit();\n    \n    return fails;\n}\n\n"
  },
  {
    "path": "test/common/tests.h",
    "content": "/* \n   Stupidly simple test framework\n   Copyright (C) 2001-2004, Joe Orton <joe@manyfish.co.uk>\n\n   This library is free software; you can redistribute it and/or\n   modify it under the terms of the GNU Library General Public\n   License as published by the Free Software Foundation; either\n   version 2 of the License, or (at your option) any later version.\n   \n   This library is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n   Library General Public License for more details.\n\n   You should have received a copy of the GNU Library General Public\n   License along with this library; if not, write to the Free\n   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\n   MA 02111-1307, USA\n\n*/\n\n#ifndef TESTS_H\n#define TESTS_H 1\n\n#ifdef HAVE_STRING_H\n#include <string.h>\n#endif\n\n#include <stdio.h>\n\n#define OK 0\n#define FAIL 1\n#define FAILHARD 2 /* fail and skip all succeeding tests in this suite. */\n#define SKIP 3 /* test was skipped because precondition was not met */\n#define SKIPREST 4 /* skipped, and skip all succeeding tests in suite */\n\n/* A test function. Must return any of OK, FAIL, FAILHARD, SKIP, or\n * SKIPREST.  May call t_warning() any number of times.  If not\n * returning OK, optionally call t_context to provide an error\n * message. */\ntypedef int (*test_func)(void);\n\ntypedef struct {\n    test_func fn; /* the function to test. */\n    const char *name; /* the name of the test. */\n    int flags;\n} ne_test;\n\n/* possible values for flags: */\n#define T_CHECK_LEAKS (1) /* check for memory leaks */\n#define T_EXPECT_FAIL (2) /* expect failure */\n#define T_EXPECT_LEAKS (4) /* expect memory leak failures */\n\n/* array of tests to run: must be defined by each test suite. */\nextern ne_test tests[];\n\n/* define a test function which has the same name as the function,\n * and does check for memory leaks. */\n#define T(fn) { fn, #fn, T_CHECK_LEAKS }\n/* define a test function which is expected to return FAIL. */\n#define T_XFAIL(fn) { fn, #fn, T_EXPECT_FAIL | T_CHECK_LEAKS }\n/* define a test function which isn't checked for memory leaks. */\n#define T_LEAKY(fn) { fn, #fn, 0 }\n/* define a test function which is expected to fail memory leak checks */\n#define T_XLEAKY(fn) { fn, #fn, T_EXPECT_LEAKS }\n/* named test function. */\n#define T_NAMED(fn, name) { fn, name, T_CHECK_LEAKS }\n\n#ifdef NEON_TEST_INIT\n/* If the NEON_TEST_INIT macro is defined, it defines a function which\n * will be called to parse the argv array, and can optionally disable\n * use of colour or enable quiet output.  The main() function will\n * bail out if the function returns non-zero. */\nint NEON_TEST_INIT(int argc, const char *const *argv, int *use_colour, int *quiet);\n#endif\n\n/* current test number */\nextern int test_num;\n\n/* name of test suite */\nextern const char *test_suite;\n\n/* Provide result context message. */\nvoid t_context(const char *ctx, ...)\n#ifdef __GNUC__\n                __attribute__ ((format (printf, 1, 2)))\n#endif /* __GNUC__ */\n    ;\n\nextern char test_context[];\n\n/* the command-line arguments passed in to the test suite: */\nextern char **test_argv;\nextern int test_argc;\n\n/* child process should call this. */\nvoid in_child(void);\n\n/* issue a warning. */\nvoid t_warning(const char *str, ...)\n#ifdef __GNUC__\n                __attribute__ ((format (printf, 1, 2)))\n#endif /* __GNUC__ */\n;\n\n/* Macros for easily writing is-not-zero comparison tests; the ON*\n * macros fail the function if a comparison is not zero.\n *\n * ONV(x,vs) takes a comparison X, and a printf varargs list for\n * the failure message.\n *  e.g.   ONV(strcmp(bar, \"foo\"), (\"bar was %s not 'foo'\", bar))\n *\n * ON(x) takes a comparison X, and uses the line number for the failure\n * message.   e.g.  ONV(strcmp(bar, \"foo\"))\n *\n * ONN(n, x) takes a comparison X, and a flat string failure message.\n *  e.g.  ONN(\"foo was wrong\", strcmp(bar, \"foo\")) */\n\n#define ONV(x,vs) do { if ((x)) { t_context vs; return FAIL; } } while (0)\n#define ON(x) ONV((x), (\"line %d\", __LINE__ ))\n#define ONN(n,x) ONV((x), (n))\n\n/* ONCMP(exp, act, name): 'exp' is the expected string, 'act' is the\n * actual string for some field 'name'.  Succeeds if strcmp(exp,act)\n * == 0 or both are NULL. */\n#define ONCMP(exp, act, ctx, name) do { \\\n        ONV(exp && !act, (\"%s: \" name \" was NULL, expected '%s'\", ctx, exp)); \\\n        ONV(!exp && act, (\"%s: \" name \" was '%s', expected NULL\", ctx, act)); \\\n        ONV(exp && strcmp(exp, act), (\"%s: \" name \" was '%s' not '%s'\", ctx, act, exp)); \\\n} while (0)\n\n/* Variant of ONCMP(), 'exp' and 'act' are known to be non-NULL. */\n#define ONCMPN(exp, act, ctx, name) \\\n    ONV(strcmp(exp, act), (\"%s: \" name \" was '%s' not '%s'\", ctx, act, exp))\n\n/* return immediately with result of test 'x' if it fails. */\n#define CALL(x) do { int t_ret = (x); if (t_ret != OK) return t_ret; } while (0)\n\n/* PRECOND: skip current test if condition 'x' is not true. */\n#define PRECOND(x) do { if (!(x)) { return SKIP; } } while (0)\n\n#endif /* TESTS_H */\n"
  },
  {
    "path": "test/compress.c",
    "content": "/* \n   tests for compressed response handling.\n   Copyright (C) 2001-2008, Joe Orton <joe@manyfish.co.uk>\n\n   This program is free software; you can redistribute it and/or modify\n   it under the terms of the GNU General Public License as published by\n   the Free Software Foundation; either version 2 of the License, or\n   (at your option) any later version.\n  \n   This program is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU General Public License for more details.\n  \n   You should have received a copy of the GNU General Public License\n   along with this program; if not, write to the Free Software\n   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\n*/\n\n#include \"config.h\"\n\n#ifdef HAVE_UNISTD_H\n#include <unistd.h>\n#endif\n\n#include \"ne_compress.h\"\n#include \"ne_auth.h\"\n\n#include \"tests.h\"\n#include \"child.h\"\n#include \"utils.h\"\n\nstatic enum { f_partial = 0, f_mismatch, f_complete } failed;\n\nstatic const char newsfn[] = \"random.txt\", hellofn[] = \"hello.txt\";\n\nstatic int init(void)\n{\n    return lookup_localhost();\n}\n\n#define EXTRA_DEBUG 0 /* disabled by default */\n\nstatic int reader(void *ud, const char *block, size_t len)\n{\n    struct string *b = ud;\n\n#if EXTRA_DEBUG\n    NE_DEBUG(NE_DBG_HTTP, \"reader: got (%d): [[[%.*s]]]\\n\", (int)len,\n             (int)len, block);\n#endif\n\n    if (failed == f_mismatch) return -1;\n\n    /* catch multiple len == 0 call as issued by 0.25.0 only: */\n    if (failed == f_complete) {\n        NE_DEBUG(NE_DBG_HTTP, \"reader: called after complete, len=%d\\n\",\n                 (int)len);\n        failed = f_mismatch;\n        return -1;\n    }\n\n    if (failed == f_partial && len == 0) {\n        if (b->len != 0) {\n            NE_DEBUG(NE_DBG_HTTP, \"reader: got length %d at EOF\\n\",\n                     (int)b->len);\n            failed = f_mismatch;\n        } else {\n            failed = f_complete;\n        }\n        return 0;\n    }\n\n    if (len > b->len || memcmp(b->data, block, len) != 0) {\n        NE_DEBUG(NE_DBG_HTTP, \"reader: failed, got [[%.*s]] not [[%.*s]]\\n\",\n                 (int)len, block, (int)b->len, b->data);\n\tfailed = f_mismatch;\n        return -1;\n    } else {\n\tb->data += len;\n\tb->len -= len;\n#if EXTRA_DEBUG\n        NE_DEBUG(NE_DBG_HTTP, \"reader: OK, %d bytes remaining\\n\", \n                 (int)b->len);\n#endif\n    }\n\n    return 0;\n}\n\nstatic int do_fetch(const char *realfn, const char *gzipfn,\n\t\t    int chunked, int expect_fail)\n{\n    ne_session *sess;\n    ne_request *req;\n    int ret;\n    ne_buffer *buf = ne_buffer_create();\n    struct serve_file_args sfargs;\n    ne_decompress *dc;\n    struct string body;\n    \n    CALL(file_to_buffer(realfn, buf));\n\n    body.data = buf->data;\n    body.len = buf->used - 1;\n    \n    failed = f_partial;\n\n    if (gzipfn) {\n\tsfargs.fname = gzipfn;\n\tsfargs.headers = \"Content-Encoding: gzip\\r\\n\";\n    } else {\n\tsfargs.fname = realfn;\n\tsfargs.headers = NULL;\n    }\n    sfargs.chunks = chunked;\n    \n    CALL(make_session(&sess, serve_file, &sfargs));\n    \n    req = ne_request_create(sess, \"GET\", \"/\");\n    dc = ne_decompress_reader(req, ne_accept_2xx, reader, &body);\n\n#ifdef NE_DEBUGGING\n    ne_debug_init(ne_debug_stream, ne_debug_mask & ~NE_DBG_HTTPBODY);\n#endif\n\n    ret = ne_request_dispatch(req);\n\n#ifdef NE_DEBUGGING\n    ne_debug_init(ne_debug_stream, ne_debug_mask | NE_DBG_HTTPBODY);\n#endif\n\n    ONN(\"file not served\", ne_get_status(req)->code != 200);\n    \n    ONN(\"decompress succeeded\", expect_fail && !ret);\n    ONV(!expect_fail && ret, (\"decompress failed: %s\", ne_get_error(sess)));\n\n    NE_DEBUG(NE_DBG_HTTP, \"session error: %s\\n\", ne_get_error(sess));\n\n    ne_decompress_destroy(dc);\n    ne_request_destroy(req);\n    ne_session_destroy(sess);\n    ne_buffer_destroy(buf);\n\n    if (expect_fail) {\n        /* if the decompress callback fails, the connection may\n         * be aborted and hence the server will abort. */\n        reap_server();\n    } else {\n        CALL(await_server());\n    }\n\n    if (!expect_fail) {\n        ONN(\"inflated response truncated\", failed == f_partial);\n        ONN(\"inflated response mismatch\", failed == f_mismatch);\n    }\n\n    return OK;\n}\n\nstatic int fetching(void)\n{\n    static const struct {\n        const char *realfn;\n        const char *gzipfn;\n        int chunked;\n        int expect_fail;\n    } ts[] = {\n        /* not_compressed */\n        { newsfn, NULL, 0, 0 },\n        /* simple */\n        { newsfn, \"file1.gz\", 0, 0 },\n        /* hello */\n        { hellofn, \"hello.gz\", 0, 0 },\n        /* withname */\n        { newsfn, \"file2.gz\", 0, 0 },\n        /* chunked_1b_wn */\n        { newsfn, \"file2.gz\", 1, 0 },\n        /* chunked_1b */\n        { newsfn, \"file1.gz\", 1, 0 },\n        /* chunked_12b */\n        { newsfn, \"file2.gz\", 12, 0 },\n        /* chunked_20b */\n        { newsfn, \"file2.gz\", 20, 0 },\n        /* chunked_10b */\n        { newsfn, \"file1.gz\", 10, 0 },\n        /* chunked_10b_wn */\n        { newsfn, \"file2.gz\", 10, 0 },\n        /* notcomp_empty */\n        { \"empty.gz\", NULL, 0, 0 },\n        /* fail_trailing */\n        { newsfn, \"trailing.gz\", 0, 1 },\n        /* fail_trailing_1b */\n        { newsfn, \"trailing.gz\", 1, 1 },\n        /* fail_truncate */\n        { newsfn, \"truncated.gz\", 0, 1 },\n        /* fail_bad_csum */\n        { newsfn, \"badcsum.gz\", 0, 1 },\n        /* fail_corrupt1 */\n        { newsfn, \"corrupt1.gz\", 0, 1 },\n        /* fail_corrupt2 */\n        { newsfn, \"corrupt2.gz\", 0, 1 },\n        /* fail_empty */\n        { newsfn, \"empty.gz\", 0, 1 },\n        { NULL, NULL, 0, 0 }\n    };\n    unsigned i;\n\n    for (i = 0; ts[i].realfn != NULL; i++) {\n        CALL(do_fetch(ts[i].realfn, ts[i].gzipfn, ts[i].chunked, ts[i].expect_fail));\n    }\n\n    return OK;\n}\n\nstatic int auth_cb(void *userdata, const char *realm, int tries, \n\t\t   char *un, char *pw)\n{\n    strcpy(un, \"foo\");\n    strcpy(pw, \"bar\");\n    return tries;\n}\n\nstatic int retry_compress_helper(ne_accept_response acceptor,\n                                 struct double_serve_args *args, \n                                 struct string *expect)\n{\n    ne_session *sess;\n    ne_request *req;\n    ne_decompress *dc;\n    \n    CALL(make_session(&sess, double_serve_sstring, args));\n\n    ne_set_server_auth(sess, auth_cb, NULL);\n\n    req = ne_request_create(sess, \"GET\", \"/\");\n    dc = ne_decompress_reader(req, acceptor, reader, expect);\n    failed = f_partial;\n\n    ONREQ(ne_request_dispatch(req));\n    \n    ne_decompress_destroy(dc);\n\n    ONN(\"got bad response body\", failed != f_complete);\n\n    ne_request_destroy(req);\n\n    return destroy_and_wait(sess);\n}\n\n#define SSTRING(x) { x, sizeof(x) - 1 }\n\nstatic struct double_serve_args retry_gz_args = { \n    SSTRING(\"HTTP/1.1 401 Get Away\\r\\n\"\n            \"Content-Encoding: gzip\\r\\n\"\n            \"WWW-Authenticate: Basic realm=WallyWorld\\r\\n\"\n            \"Content-Length: 5\\r\\n\"\n            \"\\r\\n\"\n            \"abcde\"),\n    SSTRING(\"HTTP/1.1 200 OK\\r\\n\"\n            \"Server: foo\\r\\n\"\n            \"Content-Length: 5\\r\\n\"\n            \"Connection: close\\r\\n\"\n            \"\\r\\n\"\n            \"hello\")\n};\n\n/* Test where the response to the retried request does *not* have\n * a content-encoding, whereas the original 401 response did. */\nstatic int retry_notcompress(void)\n{\n    struct string expect = { \"hello\", 5 };\n    return retry_compress_helper(ne_accept_2xx, &retry_gz_args, &expect);\n}\n\nstatic struct double_serve_args retry_gz_args2 = {\n    SSTRING(\"HTTP/1.1 401 Get Away\\r\\n\"\n            \"Content-Encoding: gzip\\r\\n\"\n            \"WWW-Authenticate: Basic realm=WallyWorld\\r\\n\"\n            \"Content-Length: 25\\r\\n\"\n            \"\\r\\n\"\n            \"\\x1f\\x8b\\x08\\x00\\x00\\x00\\x00\\x00\\x00\\x03\\xcb\\x48\\xcd\\xc9\\xc9\\x07\"\n            \"\\x00\\x86\\xa6\\x10\\x36\\x05\\x00\\x00\\x00\"),\n    SSTRING(\"HTTP/1.1 200 OK\\r\\n\"\n            \"Server: foo\\r\\n\"\n            \"Content-Encoding: gzip\\r\\n\"\n            \"Content-Length: 25\\r\\n\"\n            \"Connection: close\\r\\n\"\n            \"\\r\\n\"\n            \"\\x1f\\x8b\\x08\\x00\\x00\\x00\\x00\\x00\\x00\\x03\\x2b\\xcf\\x2f\\xca\\x49\\x01\"\n            \"\\x00\\x43\\x11\\x77\\x3a\\x05\\x00\\x00\\x00\")\n};\n\nstatic int retry_accept(void *ud, ne_request *req, const ne_status *st)\n{\n    struct string *expect = ud;\n\n    NE_DEBUG(NE_DBG_HTTP, \"retry_accept callback for %d response\\n\",\n             st->code);\n\n    if (expect->len == 4 && strcmp(expect->data, \"fish\") == 0) {\n        /* first time through */\n        expect->data = \"hello\";\n    } else {\n        expect->data = \"world\";\n    }\n\n    expect->len = 5;\n    failed = f_partial; /* reset the state */\n    return 1;\n}\n\n/* Test where the response to the retried request *does* have a\n * content-encoding, as did the original 401 response. */\nstatic int retry_compress(void)\n{\n    struct string expect = { \"fish\", 4 };\n    return retry_compress_helper(retry_accept, &retry_gz_args2, &expect);\n}\n\n#define READER_ABORT_ERR \"reader_abort error string\"\n\nstatic int reader_abort(void *ud, const char *buf, size_t len)\n{\n    ne_session *sess = ud;\n    ne_set_error(sess, READER_ABORT_ERR);\n    return len;\n}\n\n/* check that a callback abort does abort the response */\nstatic int compress_abort(void)\n{\n    ne_session *sess;\n    ne_request *req;\n    struct serve_file_args sfargs;\n    ne_decompress *dc;\n    int ret;\n\n    sfargs.fname = \"file1.gz\";\n    sfargs.headers = \"Content-Encoding: gzip\\r\\n\";\n    sfargs.chunks = 0;\n\n    CALL(make_session(&sess, serve_file, &sfargs));\n\n    req = ne_request_create(sess, \"GET\", \"/abort\");\n\n    dc = ne_decompress_reader(req, ne_accept_2xx, reader_abort, sess);\n\n    ret = ne_request_dispatch(req);\n\n    reap_server();\n\n    ONN(\"request was not aborted\", ret != NE_ERROR);\n    ONV(strcmp(ne_get_error(sess), READER_ABORT_ERR),\n        (\"session error was %s not %s\",\n         ne_get_error(sess), READER_ABORT_ERR));\n    \n    reap_server();\n    ne_decompress_destroy(dc);\n    ne_request_destroy(req);\n    ne_session_destroy(sess);\n\n    return OK;\n\n}\n\nne_test tests[] = {\n    T_LEAKY(init),\n    T(fetching),\n    T(retry_notcompress),\n    T(retry_compress),\n    T(compress_abort),\n    T(NULL)\n};\n"
  },
  {
    "path": "test/expired.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIDODCCAuKgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBoTELMAkGA1UEBhMCR0Ix\nFzAVBgNVBAgTDkNhbWJyaWRnZXNoaXJlMRIwEAYDVQQHEwlDYW1icmlkZ2UxGjAY\nBgNVBAoTEU5lb24gSGFja2VycyBMdGQuMRUwEwYDVQQLEwxOZW9uIFFBIERlcHQx\nEjAQBgNVBAMTCWxvY2FsaG9zdDEeMBwGCSqGSIb3DQEJARYPbmVvbkB3ZWJkYXYu\nb3JnMB4XDTAyMDEyMTIwMzkwNFoXDTAyMDEzMTIwMzkwNFowgaExCzAJBgNVBAYT\nAkdCMRcwFQYDVQQIEw5DYW1icmlkZ2VzaGlyZTESMBAGA1UEBxMJQ2FtYnJpZGdl\nMRowGAYDVQQKExFOZW9uIEhhY2tlcnMgTHRkLjEVMBMGA1UECxMMTmVvbiBRQSBE\nZXB0MRIwEAYDVQQDEwlsb2NhbGhvc3QxHjAcBgkqhkiG9w0BCQEWD25lb25Ad2Vi\nZGF2Lm9yZzBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQDzRU5sZ8+CWQPvPkqJw9Kl\noEgT2FqzZR9RT/qbJuRBmRphiRr0g7JOh5Mr7LXaKShedFLhGidutyKKwIZJnRht\nAgMBAAGjggEBMIH+MB0GA1UdDgQWBBRFA3ktzHSuD9uB6mJOWoElmOtknzCBzgYD\nVR0jBIHGMIHDgBRFA3ktzHSuD9uB6mJOWoElmOtkn6GBp6SBpDCBoTELMAkGA1UE\nBhMCR0IxFzAVBgNVBAgTDkNhbWJyaWRnZXNoaXJlMRIwEAYDVQQHEwlDYW1icmlk\nZ2UxGjAYBgNVBAoTEU5lb24gSGFja2VycyBMdGQuMRUwEwYDVQQLEwxOZW9uIFFB\nIERlcHQxEjAQBgNVBAMTCWxvY2FsaG9zdDEeMBwGCSqGSIb3DQEJARYPbmVvbkB3\nZWJkYXYub3JnggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADQQBDSFbe\n9EjP+IyZ4vhJSk66gLSN8CnafoGm5JHpNOHy5gWLh7j0a/dxWRd4gpoBYBB6Y9rO\nYV6Eq3njdj0gu+NN\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "test/htdocs/plain",
    "content": "Test file.\n"
  },
  {
    "path": "test/largefile.c",
    "content": "/* \n   Tests for LFS support in neon\n   Copyright (C) 2004-2006, Joe Orton <joe@manyfish.co.uk>\n\n   This program is free software; you can redistribute it and/or modify\n   it under the terms of the GNU General Public License as published by\n   the Free Software Foundation; either version 2 of the License, or\n   (at your option) any later version.\n  \n   This program is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU General Public License for more details.\n  \n   You should have received a copy of the GNU General Public License\n   along with this program; if not, write to the Free Software\n   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\n*/\n\n#include \"config.h\"\n\n#include <sys/types.h>\n\n#include <unistd.h>\n#include <fcntl.h>\n\n#ifdef HAVE_STDINT_H\n#include <stdint.h>\n#endif\n\n#include \"ne_request.h\"\n\n#include \"child.h\"\n#include \"utils.h\"\n#include \"tests.h\"\n\n#ifndef INT64_C\n#define INT64_C(x) x ## LL\n#endif\n\nstatic const char data[] = \"Hello, world.\\n\";\nstatic off64_t point = INT64_C(2) << 32;\n#define SPARSE \"sparse.bin\"\n\n/* make a sparse large file */\nstatic int make_sparse_file(void)\n{\n    int fd = open64(SPARSE, O_CREAT | O_TRUNC | O_WRONLY, 0644);\n\n    ONN(\"could not create large file \" SPARSE, fd < 0);\n    ONN(\"seek to point\", lseek64(fd, point, SEEK_SET) != point);\n    ONN(\"could not write to file\", \n        write(fd, data, strlen(data)) != (ssize_t)strlen(data));\n    ONN(\"close failed\", close(fd));\n    \n    return OK;\n}\n\n/* server function which checks that the request body sent was the\n * same as the 'data' array. */\nstatic int serve_check_body(ne_socket *sock, void *userdata)\n{\n    CALL(discard_request(sock));\n\n    if (clength != (ssize_t)strlen(data)) {\n        CALL(discard_body(sock));\n        SEND_STRING(sock, \"HTTP/1.0 400 Bad Request Body Length\\r\\n\"\n                    \"\\r\\n\");\n    } else {\n        char buf[20];\n        \n        if (ne_sock_fullread(sock, buf, clength) == 0) {\n            SEND_STRING(sock, \"HTTP/1.0 200 OK Then!\\r\\n\\r\\n\");\n        }\n    }\n    return 0;\n}\n\n/* sends a small segment of the file from a high offset. */\nstatic int send_high_offset(void)\n{\n    int ret, fd = open64(SPARSE, O_RDONLY);\n    ne_session *sess;\n    ne_request *req;\n\n    ONN(\"could not open sparse file\", fd < 0);\n\n    CALL(make_session(&sess, serve_check_body, NULL));\n    \n    req = ne_request_create(sess, \"PUT\", \"/sparse\");\n    ne_set_request_body_fd(req, fd, point, strlen(data));\n    ret = ne_request_dispatch(req);\n    CALL(await_server());\n    ONV(ret != NE_OK || ne_get_status(req)->klass != 2,\n        (\"request failed: %s\", ne_get_error(sess)));\n    ne_request_destroy(req);\n    ne_session_destroy(sess);\n    close(fd);\n    return OK;\n}\n\n#if 1\n#define RESPSIZE INT64_C(4295008256)\n#define RESPSTR \"4295008256\"\n#else\n#define RESPSIZE INT64_C(2147491840) /* 2^31+8192 */\n#define RESPSTR \"2147491840\" \n#endif\n\n/* Reads a request, sends a large response, reads a request, then\n * sends a little response. */\nstatic int serve_large_response(ne_socket *sock, void *ud)\n{\n    int n = 0;\n    char empty[8192];\n\n    CALL(discard_request(sock));\n\n    SEND_STRING(sock, \n                \"HTTP/1.1 200 OK\\r\\n\"\n                \"Content-Length: \" RESPSTR \"\\r\\n\"\n                \"Server: BigFileServerTM\\r\\n\" \"\\r\\n\");\n    \n    memset(empty, 0, sizeof empty);\n\n    for (n = 0; n < RESPSIZE/sizeof(empty); n++) {\n        if (ne_sock_fullwrite(sock, empty, sizeof empty)) {\n            NE_DEBUG(NE_DBG_SOCKET, \"fullwrite failed\\n\");\n            return 1;\n        }\n    }\n\n    NE_DEBUG(NE_DBG_SOCKET, \"Wrote %d lots of %d\\n\", n, (int)sizeof empty);\n    \n    CALL(discard_request(sock));\n\n    SEND_STRING(sock, \"HTTP/1.1 200 OK\\r\\n\"\n                \"Connection: close\\r\\n\\r\\n\");\n    \n    return 0;\n}\n\nstatic int read_large_response(void)\n{\n    ne_session *sess;\n    ne_request *req;\n    off64_t count = 0;\n    int ret;\n    char buf[8192];\n#ifdef NE_DEBUGGING\n    int old_mask = ne_debug_mask;\n#endif\n\n    CALL(make_session(&sess, serve_large_response, NULL));\n\n    req = ne_request_create(sess, \"GET\", \"/foo\");\n\n    ret = ne_begin_request(req);\n\n#ifdef NE_DEBUGGING\n    ne_debug_init(ne_debug_stream, ne_debug_mask & ~(NE_DBG_HTTPBODY|NE_DBG_HTTP));\n#endif\n\n    if (ret == NE_OK) {\n        while ((ret = ne_read_response_block(req, buf, sizeof buf)) > 0)\n            count += ret;\n        if (ret == NE_OK)\n            ret = ne_end_request(req);\n    }\n\n#ifdef NE_DEBUGGING\n    ne_debug_init(ne_debug_stream, old_mask);\n#endif\n        \n    ONV(ret, (\"request failed: %s\", ne_get_error(sess)));\n    ONV(count != RESPSIZE, \n        (\"response body was %\" NE_FMT_OFF64_T \" not %\" NE_FMT_OFF64_T,\n         count, RESPSIZE));\n\n    ne_request_destroy(req);\n\n    CALL(any_2xx_request(sess, \"/bar\"));\n\n    return destroy_and_wait(sess);\n}\n\nne_test tests[] = {\n    T(make_sparse_file),\n    T(send_high_offset),\n    T(read_large_response),\n    T(NULL),\n};\n"
  },
  {
    "path": "test/lock.c",
    "content": "/* \n   lock tests\n   Copyright (C) 2002-2026, Joe Orton <joe@manyfish.co.uk>\n\n   This program is free software; you can redistribute it and/or modify\n   it under the terms of the GNU General Public License as published by\n   the Free Software Foundation; either version 2 of the License, or\n   (at your option) any later version.\n  \n   This program is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU General Public License for more details.\n  \n   You should have received a copy of the GNU General Public License\n   along with this program; if not, write to the Free Software\n   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\n*/\n\n#include \"config.h\"\n\n#include <sys/types.h>\n\n#ifdef HAVE_STDLIB_H\n#include <stdlib.h>\n#endif\n#ifdef HAVE_UNISTD_H\n#include <unistd.h>\n#endif\n\n#include \"ne_request.h\"\n#include \"ne_locks.h\"\n#include \"ne_socket.h\"\n#include \"ne_basic.h\"\n#include \"ne_auth.h\"\n\n#include \"tests.h\"\n#include \"child.h\"\n#include \"utils.h\"\n\n#define EOL \"\\r\\n\"\n\n#define FOO_LOCKROOT \"http://localhost/foo\"\n\n/* returns an activelock XML element. */\nstatic char *activelock(enum ne_lock_scope scope,\n                        int depth,\n                        const char *owner,\n                        const char *uri,\n                        unsigned long timeout,\n                        const char *token_href)\n{\n    static char buf[BUFSIZ];\n    const char *lr_start = uri != NULL ? \"<D:lockroot><D:href>\" : \"\";\n    const char *lr_end = uri != NULL ? \"</D:href></D:lockroot>\\n\" : \"\";\n    \n    ne_snprintf(buf, BUFSIZ,                                            \\\n                \"<D:activelock>\\n\"                                      \\\n                \"<D:locktype><D:write/></D:locktype>\\n\"                 \\\n                \"<D:lockscope><D:%s/></D:lockscope>\\n\"                  \\\n                \"<D:depth>%d</D:depth>\\n\"                               \\\n                \"<D:owner>%s</D:owner>\\n\"                               \\\n                \"<D:timeout>Second-%lu</D:timeout>\\n\"                   \\\n                \"<D:locktoken><D:href>%s</D:href></D:locktoken>\\n\"      \\\n                \"%s%s%s\"                                                \\\n                \"</D:activelock>\",                                      \\\n                scope==ne_lockscope_exclusive?\"exclusive\":\"shared\",     \\\n                depth, owner, timeout, token_href,                      \\\n                lr_start, uri ? uri : \"\", lr_end);\n\n    return buf;\n}\t\n\n/* return body of LOCK response for given lock. */\nstatic char *lock_response(enum ne_lock_scope scope,\n\t\t\t   int depth,\n\t\t\t   const char *owner,\n                           const char *uri,\n\t\t\t   unsigned long timeout,\n\t\t\t   const char *token_href)\n{\n    static char buf[BUFSIZ];\n\n    ne_snprintf(buf, sizeof buf,\n                \"<?xml version=\\\"1.0\\\" encoding=\\\"utf-8\\\"?>\\n\"\n                \"<D:prop xmlns:D=\\\"DAV:\\\">\"\n                \"<D:lockdiscovery>%s</D:lockdiscovery></D:prop>\\n\",\n                activelock(scope, depth, owner, uri, timeout, token_href));\n\n    return buf;\n}\n\n/* return body of LOCK response where response gives multiple\n * activelocks (i.e. shared locks). */\nstatic char *multi_lock_response(struct ne_lock **locks)\n{\n    ne_buffer *buf = ne_buffer_create();\n    int n;\n\n    ne_buffer_zappend(buf,\n\t\t      \"<?xml version=\\\"1.0\\\" encoding=\\\"utf-8\\\"?>\\n\"\n\t\t      \"<D:prop xmlns:D=\\\"DAV:\\\">\"\n\t\t      \"<D:lockdiscovery>\");\n    \n    for (n = 0; locks[n] != NULL; n++) {\n        char *lk = activelock(locks[n]->scope, locks[n]->depth,\n                              locks[n]->owner, NULL,\n                              locks[n]->timeout, locks[n]->token);\n\tne_buffer_zappend(buf, lk);\n    }\n\n    ne_buffer_zappend(buf, \"</D:lockdiscovery></D:prop>\");\n    return ne_buffer_finish(buf);\n}\n\nstatic char *discover_response(const char *href, const struct ne_lock *lk)\n{\n    char buf[BUFSIZ];\n    char *uri = ne_uri_unparse(&lk->uri);\n\n    ne_snprintf(buf, BUFSIZ,\n\t\t\"<?xml version=\\\"1.0\\\" encoding=\\\"utf-8\\\"?>\\n\"\n\t\t\"<D:multistatus xmlns:D='DAV:'>\\n\"\n\t\t\"<D:response><D:href>%s</D:href><D:propstat>\\n\"\n\t\t\"<D:prop><D:lockdiscovery>%s</D:lockdiscovery></D:prop>\\n\"\n\t\t\"<D:status>HTTP/1.1 200 OK</D:status></D:propstat>\\n\"\n\t\t\"</D:response></D:multistatus>\\n\",\n\t\thref, activelock(lk->scope, lk->depth, lk->owner, uri,\n\t\t\t\t 7200, lk->token));\n\n    ne_free(uri);\n\n    return ne_strdup(buf);\n}\n\nstatic struct ne_lock *make_lock(const char *path, const char *token,\n\t\t\t\t enum ne_lock_scope scope, int depth)\n{\n    struct ne_lock *lock = ne_calloc(sizeof *lock);\n\n    if (lock->token) lock->token = ne_strdup(token);\n    lock->scope = scope;\n    lock->depth = depth;\n    lock->uri.host = ne_strdup(\"localhost\");\n    lock->uri.scheme = ne_strdup(\"http\");\n    lock->uri.path = ne_strdup(path);\n    lock->uri.port = 7777;\n\n    return lock;\n}\n\n/* Tests for lock store handling. */\nstatic int store_single(void)\n{\n    ne_lock_store *store = ne_lockstore_create();\n    struct ne_lock *lk = make_lock(\"/foo\", \"blah\", ne_lockscope_exclusive, 0);\n    struct ne_lock *lk2;\n\n    ONN(\"create failed\", store == NULL);\n\n    ONN(\"new lock store not empty\", ne_lockstore_first(store) != NULL);\n\n    ne_lockstore_add(store, lk);\n\n    ONN(\"lock not found in store\", ne_lockstore_first(store) != lk);\n\n    ONN(\">1 locks in store?\", ne_lockstore_next(store) != NULL);\n\n    lk2 = ne_lockstore_findbyuri(store, &lk->uri);\n\n    ONN(\"lock not found by URI\", lk2 == NULL);\n    ONN(\"other lock found by URI\", lk2 != lk);\n    \n    ne_lockstore_remove(store, lk);\n\n    ONN(\"store not empty after removing lock\",\n\tne_lockstore_first(store) != NULL);\n\n    ONN(\"lock still found after removing lock\",\n\tne_lockstore_findbyuri(store, &lk->uri) != NULL);\n\n    ne_lockstore_destroy(store);\n    ne_lock_destroy(lk);\n    \n    return OK;\n}\n\nstatic int store_several(void)\n{\n    ne_lock_store *store = ne_lockstore_create();\n    struct ne_lock *lk = make_lock(\"/foo\", \"blah\", ne_lockscope_exclusive, 0);\n    struct ne_lock *lk2 = make_lock(\"/bar\", \"blee\", ne_lockscope_exclusive, 0);\n    struct ne_lock *lf, *lf2;\n\n    ONN(\"create failed\", store == NULL);\n\n    ne_lockstore_add(store, lk);\n    ne_lockstore_add(store, lk2);\n\n    lf = ne_lockstore_first(store);\n    ONN(\"lock store empty\", lf == NULL);\n    lf2 = ne_lockstore_next(store);\n    ONN(\"lock store >2 locks\", ne_lockstore_next(store) != NULL);\n\n    /* guarantee that _first, _next returned either of the\n     * combinations: (lf, lf2) or (lf2, lf) */\n    ONN(\"found wrong locks\", ((lf != lk && lf != lk2) ||\n\t\t\t      (lf2 != lk && lf2 != lk2) ||\n\t\t\t      (lf == lf2)));\n\n    ONN(\"first find failed\",\n\tne_lockstore_findbyuri(store, &lk->uri) != lk);\n    ONN(\"second find failed\",\n\tne_lockstore_findbyuri(store, &lk2->uri) != lk2);\n    \n    ne_lockstore_remove(store, lk);\n    ne_lock_destroy(lk);\n\n    ONN(\"remove left stray lock?\", ne_lockstore_first(store) != lk2);\n\n    ONN(\"remove left >1 lock?\", ne_lockstore_next(store) != NULL);\n\n    ne_lockstore_remove(store, lk2);\n    ne_lock_destroy(lk2);\n\n    ONN(\"store not empty after removing all locks\",\n\tne_lockstore_first(store) != NULL);\n\n    ne_lockstore_destroy(store);\n    \n    return OK;\n}\n\n/* Use a fake session forced to use port 7777 to the origin, to\n * simplify the tests. */\nstatic int fake_session(ne_session **sess, server_fn fn, void *userdata)\n{\n    return proxied_session_server(sess, \"http\", \"localhost\", 7777,\n                                  fn, userdata);\n}\n\n/* regression test for <= 0.18.2, where timeout field was not parsed correctly. */\nstatic int lock_timeout(void)\n{\n    ne_session *sess;\n    char *resp, *rbody = lock_response(ne_lockscope_exclusive, 0, \"me\",\n                                       NULL, 6500, \"opaquelocktoken:foo\");\n    struct ne_lock *lock = ne_lock_create();\n\n    resp = ne_concat(\"HTTP/1.1 200 OK\\r\\n\" \"Server: neon-test-server\\r\\n\"\n\t\t     \"Content-type: application/xml\" EOL\n\t\t     \"Lock-Token: <opaquelocktoken:foo>\" EOL\n\t\t     \"Connection: close\\r\\n\\r\\n\", rbody, NULL);\n\n    CALL(fake_session(&sess, single_serve_string, resp));\n    ne_free(resp);\n\n    ne_fill_server_uri(sess, &lock->uri);\n    lock->uri.path = ne_strdup(\"/foo\");\n    lock->timeout = 5;\n\n    ONREQ(ne_lock(sess, lock));\n\n    ONN(\"lock timeout ignored in response\",\n\tlock->timeout != 6500);\n\n    ne_session_destroy(sess);\n    ne_lock_destroy(lock);\n\n    CALL(await_server());\n\n    return OK;\n}\n\n#define LONG_TIMEOUT (4294967295UL)\n\n/* Lock timeouts should be allowed up to 2^32-1, but ne_lock uses a\n * signed long to store timeouts, so this would fail with 32-bit long. */\nstatic int lock_long_timeout(void)\n{\n    ne_session *sess;\n    char *resp, *rbody = lock_response(ne_lockscope_exclusive, 0, \"me\", FOO_LOCKROOT,\n                                       LONG_TIMEOUT, \"opaquelocktoken:foo\");\n    struct ne_lock *lock = ne_lock_create();\n\n    resp = ne_concat(\"HTTP/1.1 200 OK\\r\\n\" \"Server: neon-test-server\\r\\n\"\n                     \"Content-type: application/xml\" EOL\n                     \"Lock-Token: <opaquelocktoken:foo>\" EOL\n                     \"Connection: close\\r\\n\\r\\n\", rbody, NULL);\n\n    CALL(fake_session(&sess, single_serve_string, resp));\n    ne_free(resp);\n\n    ne_fill_server_uri(sess, &lock->uri);\n    lock->uri.path = ne_strdup(\"/foo\");\n    lock->timeout = 5;\n\n    ONREQ(ne_lock(sess, lock));\n\n    ne_session_destroy(sess);\n    ne_lock_destroy(lock);\n\n    CALL(await_server());\n\n    return OK;\n}\n\nstatic int verify_if;\nstatic const char *verify_if_expect;\n\nstatic void got_if_header(char *value)\n{\n    verify_if = !strcmp(verify_if_expect, value);\n    NE_DEBUG(NE_DBG_HTTP, \"Verified If header, %d: got [%s] expected [%s]\\n\", \n\t     verify_if, value, verify_if_expect);\n}\n\n/* Server callback which checks that an If: header is received. */\nstatic int serve_verify_if(ne_socket *sock, void *userdata)\n{\n    /* tell us about If headers in the request. */\n    want_header = \"If\";\n    got_header = got_if_header;\n    verify_if_expect = userdata;\n\n    verify_if = 0;\n\n    CALL(discard_request(sock));\n\n    if (verify_if) {\n\tON(SEND_STRING(sock, \"HTTP/1.1 200 OK\" EOL));\n    } else {\n\tON(SEND_STRING(sock, \"HTTP/1.1 403 Wrong If Header\" EOL));\n    }\n    \n    ON(SEND_STRING(sock, \"Connection: close\" EOL EOL));\n    \n    return OK;\n}\n\n/* Make a request which will require a lock. */\nstatic int do_request(ne_session *sess, const char *path, int depth,\n\t\t      int modparent)\n{\n    ne_request *req = ne_request_create(sess, \"RANDOM\", path);\n\n    if (depth > 0) {\n\tne_add_depth_header(req, depth);\n    }\n\n    if (depth != -1)\n\tne_lock_using_resource(req, path, depth);\n    if (modparent)\n\tne_lock_using_parent(req, path);\n\n    ONREQ(ne_request_dispatch(req));\n\n    ONV(ne_get_status(req)->code != 200,\n\t(\"request failed: %s\", ne_get_error(sess)));\n    \n    ne_request_destroy(req);\n\n    return OK;\n}\n\n/* If modparent is non-zero; the request is flagged to\n * modify the parent resource too. */\n#define LOCK_MODPARENT (0x01)\n/* Enable SharePoint hacks. */\n#define LOCK_SHAREPOINT (0x02)\n/* Use a MOVE request. */\n#define LOCK_MOVE (0x04)\n\n/* Tests If: header submission, for a lock of depth 'lockdepth' at\n * 'lockpath', with a request to 'reqpath' which Depth header of\n * 'reqdepth'.  'flags' is bitwise-or of LOCK_* flags above. */\nstatic int submit_test2(const char *lockpath, int lockdepth,\n                        const char *path1, const char *path2,\n                        int reqdepth, unsigned int flags)\n{\n    ne_lock_store *store = ne_lockstore_create();\n    ne_session *sess;\n    struct ne_lock *lk = ne_lock_create();\n    char *expect_if;\n    int ret;\n\n    if (flags & LOCK_SHAREPOINT)\n        expect_if = ne_strdup(\"(<somelocktoken>)\");\n    else\n        expect_if = ne_concat(\"<http://localhost:7777\", lockpath,\n                              \"> (<somelocktoken>)\", NULL);\n    CALL(fake_session(&sess, serve_verify_if, expect_if));\n    ne_free(expect_if);\n\n    if (flags & LOCK_SHAREPOINT)\n        ne_set_session_flag(sess, NE_SESSFLAG_SHAREPOINT, 1);\n\n    ne_fill_server_uri(sess, &lk->uri);\n    lk->uri.path = ne_strdup(lockpath);\n    lk->token = ne_strdup(\"somelocktoken\");\n    lk->depth = lockdepth;\n    \n    /* register the lock store, and add our lock for \"/foo\" to it. */\n    ne_lockstore_register(store, sess);\n    ne_lockstore_add(store, lk);\n\n    if (flags & LOCK_MOVE) {\n        ret = ne_move(sess, 0, path1, path2);\n        if (ret)\n            t_context(\"MOVE failed: %s\", ne_get_error(sess));\n    }\n    else\n        ret = do_request(sess, path1, reqdepth, flags & LOCK_MODPARENT);\n    CALL(await_server());\n\n    ne_lockstore_destroy(store);\n    ne_session_destroy(sess);\n\n    return ret;\n}\n\n/* Tests If: header submission, for a lock of depth 'lockdepth' at\n * 'lockpath', with a request to 'reqpath' which Depth header of\n * 'reqdepth'.  'flags' is bitwise-or of LOCK_* flags above. */\nstatic int submit_test(const char *lockpath, int lockdepth,\n                        const char *reqpath, int reqdepth,\n                        unsigned int flags)\n{\n    return submit_test2(lockpath, lockdepth,\n                        reqpath, NULL, reqdepth,\n                        flags);\n}\n\n\nstatic int if_simple(void)\n{\n    return submit_test(\"/foo\", 0, \"/foo\", 0, 0);\n}\n\nstatic int if_under_infinite(void)\n{\n    return submit_test(\"/foo\", NE_DEPTH_INFINITE, \"/foo/bar\", 0, 0);\n}\n\nstatic int if_infinite_over(void)\n{\n    return submit_test(\"/foo/bar\", 0, \"/foo/\", NE_DEPTH_INFINITE, 0);\n}\n\nstatic int if_child(void)\n{\n    return submit_test(\"/foo/\", 0, \"/foo/bar\", 0, LOCK_MODPARENT);\n}\n\n/* this is a special test, where the PARENT resource of \"/foo/bar\" is\n * modified, but NOT \"/foo/bar\" itself.  An UNLOCK request on a\n * lock-null resource can do this; see ne_unlock() for the comment.\n * Regression test for neon <= 0.19.3, which didn't handle this\n * correctly. */\nstatic int if_covered_child(void)\n{\n    return submit_test(\"/\", NE_DEPTH_INFINITE, \"/foo/bar\", -1,\n                       LOCK_MODPARENT);\n}\nstatic int if_sharepoint(void)\n{\n    return submit_test(\"/foo-sharepoint\", 0, \"/foo-sharepoint\", 0,\n                       LOCK_SHAREPOINT);\n}\n\nstatic int if_movefrom(void)\n{\n    return submit_test2(\"/from\", 0, \"/from/here.txt\", \"/to\", 0, LOCK_MOVE);\n}\n\nstatic int serve_discovery(ne_socket *sock, void *userdata)\n{\n    char buf[BUFSIZ], *resp = userdata;\n\n    ON(discard_request(sock));\n    ONN(\"no PROPFIND body\", clength == 0);\n    ON(ne_sock_read(sock, buf, clength) < 0);\n    ON(SEND_STRING(sock, \"HTTP/1.0 207 OK\" EOL\n                   \"Content-Type: text/xml\" EOL\n                   \"Connection: close\" EOL EOL));\n    ON(SEND_STRING(sock, resp));\n    return OK;\n}\n\nstruct result_args {\n    struct ne_lock *lock;\n    ne_uri uri;\n    int result;\n};\n\nstatic int lock_compare(const char *ctx,\n\t\t\tconst struct ne_lock *a, const struct ne_lock *b)\n{\n    ONV(!a->uri.host || !a->uri.scheme || !a->uri.path,\n\t(\"URI structure incomplete in %s\", ctx));\n    ONV(ne_uri_cmp(&a->uri, &b->uri) != 0,\n\t(\"URI comparison failed for %s: %s not %s\", ctx,\n\t ne_uri_unparse(&a->uri), ne_uri_unparse(&b->uri)));\n    ONV(a->depth != b->depth, \n\t(\"%s depth was %d not %d\", ctx, a->depth, b->depth));\n    ONV(a->scope != b->scope,\n\t(\"%s scope was %d not %d\", ctx, a->scope, b->scope));\n    ONV(a->type != b->type,\n\t(\"%s type was %d not %d\", ctx, a->type, b->type));\n    return OK;\n}\n\nstatic void discover_result(void *userdata, const struct ne_lock *lk,\n\t\t\t    const ne_uri *uri, const ne_status *st)\n{\n    struct result_args *args = userdata;\n\n    if (ne_uri_cmp(uri, &args->uri) != 0) {\n        NE_DEBUG(NE_DBG_HTTP, \"discover: URI mismatch: %s not %s\",\n                 ne_uri_unparse(uri), ne_uri_unparse(&args->uri));\n        args->result = FAIL;\n    }\n    else {\n        NE_DEBUG(NE_DBG_HTTP, \"test: Comparing discovered lock [%s] for %s \"\n                 \"with expected [%s]...\\n\",\n                 lk->token, uri->path, args->lock->token);\n        args->result = lock_compare(\"discovered lock\", lk, args->lock);\n    }\n}\n\nstatic int discover(void)\n{\n    ne_session *sess;\n    char *response;\n    int ret;\n    struct result_args args;\n\n    memset(&args, 0, sizeof args);\n    \n    args.lock = ne_lock_create();\n\n    args.lock->owner = ne_strdup(\"someowner\");\n    args.lock->token = ne_strdup(\"sometoken\");\n    args.lock->uri.host = ne_strdup(\"localhost\");\n    args.lock->uri.port = 7777;\n    args.lock->uri.scheme = ne_strdup(\"http\");\n    args.lock->uri.path = ne_strdup(\"/this/is/the/lock/path\");\n    \n    /* default */\n    args.result = FAIL;\n    t_context(\"results callback never invoked\");\n\n    response = discover_response(\"/lockme\", args.lock);\n    CALL(fake_session(&sess, serve_discovery, response));\n    ne_free(response);\n\n    ne_fill_server_uri(sess, &args.uri);\n    args.uri.path = ne_strdup(\"/lockme\");\n\n    ret = ne_lock_discover(sess, \"/lockme\", discover_result, &args);\n    CALL(await_server());\n    ONREQ(ret);\n\n    ne_lock_destroy(args.lock);\n    ne_uri_free(&args.uri);\n    ne_session_destroy(sess);\n\n    return args.result;\n}\n\n/* Check that the token for the response header */\nstatic int lock_shared(void)\n{\n    ne_session *sess;\n    char *resp, *rbody;\n    struct ne_lock *lock, *resplocks[3];\n\n#define FILLK(l, s) do { \\\n(l)->token = strdup(\"opaquelocktoken:\" s); \\\n(l)->owner = strdup(\"owner \" s); \\\n(l)->uri.path = strdup(\"/\" s); (l)->uri.host = strdup(\"localhost\"); \\\n(l)->uri.scheme = strdup(\"http\"); (l)->uri.port = 7777; } while (0)\n    \n    resplocks[0] = ne_lock_create();\n    resplocks[1] = ne_lock_create();\n    resplocks[2] = NULL;\n    FILLK(resplocks[0], \"alpha\");\n    FILLK(resplocks[1], \"beta\");\n    resplocks[0]->timeout = 100;\n    resplocks[1]->timeout = 200;\n\n    rbody = multi_lock_response(resplocks);\n    \n    resp = ne_concat(\"HTTP/1.1 200 OK\\r\\n\" \"Server: neon-test-server\\r\\n\"\n\t\t     \"Content-type: application/xml\" EOL\n\t\t     \"Lock-Token: <opaquelocktoken:beta>\" EOL\n\t\t     \"Connection: close\\r\\n\\r\\n\", rbody, NULL);\n    ne_free(rbody);\n\n    CALL(fake_session(&sess, single_serve_string, resp));\n    ne_free(resp);\n\n    lock = ne_lock_create();\n    ne_fill_server_uri(sess, &lock->uri);\n    lock->uri.path = ne_strdup(\"/beta\");\n\n    ONREQ(ne_lock(sess, lock));\n\n    CALL(await_server());\n\n    CALL(lock_compare(\"returned lock\", resplocks[1], lock));\n    \n    ne_session_destroy(sess);\n    ne_lock_destroy(lock);\n    ne_lock_destroy(resplocks[0]);\n    ne_lock_destroy(resplocks[1]);\n\n    return OK;\n}\n\nstatic void dummy_discover(void *userdata, const struct ne_lock *lock,\n                           const ne_uri *uri, const ne_status *status)\n{\n}\n\n/* This failed with neon 0.25.x and earlier when memory leak detection\n * is enabled. */\nstatic int fail_discover(void)\n{\n    ne_session *sess;\n    int ret;\n    \n    CALL(fake_session(&sess, single_serve_string, \n                      \"HTTP/1.0 207 OK\\r\\n\" \"Content-Type: text/xml\\r\\n\"\n                      \"Connection: close\\r\\n\" \"\\r\\n\"\n                      \"<?xml version=\\\"1.0\\\" encoding=\\\"utf-8\\\"?>\\n\"\n                      \"<D:multistatus xmlns:D='DAV:'>\\n\"\n                      \"<D:response><D:href>/foo/bar</D:href><D:propstat>\\n\"\n                      \"</parse this, my friend>\\n\"));\n    \n    ret = ne_lock_discover(sess, \"/foo\", dummy_discover, NULL);\n\n    ONN(\"discovery okay for response with invalid XML!?\", ret != NE_ERROR);\n\n    return destroy_and_wait(sess);\n}\n\nstatic int no_creds(void *ud, const char *realm, int attempt,\n                    char *username, char *password)\n{\n    return -1;\n}\n\nstatic int fail_lockauth(void)\n{\n    ne_session *sess;\n    struct ne_lock *lock;\n    int ret;\n    struct many_serve_args args;\n\n    args.str = \"HTTP/1.1 401 Auth Denied\\r\\n\"\n        \"WWW-Authenticate: Basic realm=\\\"realm@host\\\"\\r\\n\"\n        \"Content-Length: 0\\r\\n\"\n        \"\\r\\n\";\n    args.count = 2;\n\n    CALL(fake_session(&sess, many_serve_string, &args));\n\n    ne_set_server_auth(sess, no_creds, NULL);\n\n    lock = make_lock(\"/foo\", NULL, ne_lockscope_exclusive, NE_DEPTH_ZERO);\n    ret = ne_lock(sess, lock);\n    ONV(ret != NE_AUTH,\n        (\"attempt to lock did not fail with NE_AUTH: %d (%s)\",\n         ret, ne_get_error(sess)));\n    ne_lock_destroy(lock);\n\n    lock = make_lock(\"/bar\", \"fish\", ne_lockscope_exclusive, NE_DEPTH_ZERO);\n    lock->token = ne_strdup(\"opaquelocktoken:gah\");\n    ret  = ne_unlock(sess, lock);\n    ONV(ret != NE_AUTH,\n        (\"attempt to unlock did not fail with NE_AUTH: %d (%s)\",\n         ret, ne_get_error(sess)));\n    ne_lock_destroy(lock);\n\n    return destroy_and_wait(sess);\n}\n\n/* Regression test for neon 0.25.0 regression in ne_lock() error\n * handling. */\nstatic int fail_noheader(void)\n{\n    ne_session *sess;\n    char *resp, *rbody = lock_response(ne_lockscope_exclusive, 0, \"me\",\n                                       FOO_LOCKROOT, 6500, \"opaquelocktoken:foo\");\n    struct ne_lock *lock = ne_lock_create();\n    int ret;\n\n    resp = ne_concat(\"HTTP/1.1 200 OK\\r\\n\" \"Server: neon-test-server\\r\\n\"\n                     \"Content-type: application/xml\" EOL\n                     \"Connection: close\\r\\n\\r\\n\", rbody, NULL);\n\n    CALL(fake_session(&sess, single_serve_string, resp));\n    ne_free(resp);\n\n    ne_fill_server_uri(sess, &lock->uri);\n    lock->uri.path = ne_strdup(\"/foo\");\n    lock->timeout = NE_TIMEOUT_INFINITE;\n\n    ret = ne_lock(sess, lock);\n    ONN(\"LOCK request did not fail\", ret != NE_ERROR);\n    \n    ONV(strstr(ne_get_error(sess), \n               \"LOCK response missing Lock-Token header\") == NULL,\n        (\"unexpected error: %s\", ne_get_error(sess)));\n\n    ne_session_destroy(sess);\n    ne_lock_destroy(lock);\n\n    return await_server();\n}\n\nne_test tests[] = {\n    T(lookup_localhost),\n    T(store_single),\n    T(store_several),\n    T(if_simple),\n    T(if_under_infinite),\n    T(if_infinite_over),\n    T(if_child),\n    T(if_covered_child),\n    T(if_sharepoint),\n    T(if_movefrom),\n    T(lock_timeout),\n    T(lock_long_timeout),\n    T(lock_shared),\n    T(discover),\n    T(fail_discover),\n    T(fail_lockauth),\n    T(fail_noheader),\n    T(NULL)\n};\n\n"
  },
  {
    "path": "test/makekeys.sh",
    "content": "#!/bin/sh\n# Helper script to create CA and server certificates.\n\nsrcdir=${1-.}\n\nOPENSSL=@OPENSSL@\nCONF=${srcdir}/openssl.conf\nREQ=\"${OPENSSL} req -config ${CONF}\"\nCA=\"${OPENSSL} ca -config ${CONF} -batch\"\n# MKCERT makes a self-signed cert\nMKCERT=\"${REQ} -x509 -new -days 900\"\n\nREQDN=reqDN\nSTRMASK=default\nCADIR=./ca\nexport REQDN STRMASK CADIR\n\nasn1date() {\n\tdate -d \"$1\" \"+%y%m%d%H%M%SZ\"\n}\n\nopenssl version 1>&2\n\nset -ex\n\nfor i in ca ca1 ca2 ca3; do\n    rm -rf $i\n    mkdir $i\n    touch $i/index.txt\n    echo 01 > $i/serial\n    ${OPENSSL} genrsa -rand ${srcdir}/../configure 2048 > $i/key.pem\ndone\n\n${OPENSSL} genrsa -rand ${srcdir}/../configure 2048 > client.key\n${OPENSSL} genrsa -aes128 -passout pass:foobar -rand ${srcdir}/../configure 2048 > enclient.key\n${OPENSSL} genrsa -rand ${srcdir}/../configure 2048 > server.key\n\n${OPENSSL} dsaparam -genkey -rand ${srcdir}/../configure 1024 > client.dsap\n${OPENSSL} gendsa client.dsap > clientdsa.key\n\n${MKCERT} -key ca/key.pem -out ca/cert.pem <<EOF\nUS\nCalifornia\nOakland\nNeosign\nRandom Dept\nnowhere.example.com\nneon@webdav.org\nEOF\n\n# Function to generate appropriate output for `openssl req'.\ncsr_fields() {\nCN=${2-\"localhost\"}\nOU=${1-\"Neon QA Dept\"}\nOrg=${3-\"Neon Hackers Ltd\"}\nLocality=${4-\"Cambridge\"}\nState=${5-\"Cambridgeshire\"}\ncat <<EOF\nGB\n${State}\n${Locality}\n${Org}\n${OU}\n${CN}\nneon@webdav.org\n.\n.\nEOF\n}\n\n# Create intermediary CA\ncsr_fields IntermediaryCA | ${REQ} -new -key ca2/key.pem -out ca2.csr\n${CA} -extensions caExt -days 3560 -in ca2.csr -out ca2/cert.pem\n\ncsr_fields ExpiredCA | ${REQ} -new -key ca1/key.pem -out ca1/cert.csr\n\ncsr_fields NotYetValidCA | ${REQ} -new -key ca3/key.pem -out ca3/cert.csr\n\nCADIR=./ca1 ${CA} -name neoncainit -extensions caExt -startdate `asn1date \"2 days ago\"` -enddate `asn1date \"yesterday\"` \\\n  -in ca1/cert.csr -keyfile ca1/key.pem -out ca1/cert.pem -selfsign\n\nCADIR=./ca3 ${CA} -name neoncainit -extensions caExt -startdate `asn1date \"1 year\"` -enddate `asn1date \"2 years\"` \\\n  -in ca3/cert.csr -keyfile ca3/key.pem -out ca3/cert.pem -selfsign\n\ncsr_fields | ${REQ} -new -key server.key -out server.csr\n\ncsr_fields | ${REQ} -new -key server.key -out expired.csr\ncsr_fields | ${REQ} -new -key server.key -out notyet.csr\n\ncsr_fields \"Upper Case Dept\" lOcALhost | \\\n${REQ} -new -key server.key -out caseless.csr\n\ncsr_fields \"Use AltName Dept\" nowhere.example.com | \\\n${REQ} -new -key server.key -out altname1.csr\n\ncsr_fields \"Two AltName Dept\" nowhere.example.com | \\\n${REQ} -new -key server.key -out altname2.csr\n\ncsr_fields \"Third AltName Dept\" nowhere.example.com | \\\n${REQ} -new -key server.key -out altname3.csr\n\ncsr_fields \"Fourth AltName Dept\" localhost | \\\n${REQ} -new -key server.key -out altname4.csr\n\ncsr_fields \"Good ipAddress altname Dept\" nowhere.example.com | \\\n${REQ} -new -key server.key -out altname5.csr\n\ncsr_fields \"Bad ipAddress altname 1 Dept\" nowhere.example.com | \\\n${REQ} -new -key server.key -out altname6.csr\n\ncsr_fields \"Bad ipAddress altname 2 Dept\" nowhere.example.com | \\\n${REQ} -new -key server.key -out altname7.csr\n\ncsr_fields \"Bad ipAddress altname 3 Dept\" nowhere.example.com | \\\n${REQ} -new -key server.key -out altname8.csr\n\ncsr_fields \"Wildcard Altname Dept 1\" | \\\n${REQ} -new -key server.key -out altname9.csr\n\ncsr_fields \"Bad Hostname Department\" nohost.example.com | \\\n${REQ} -new -key server.key -out wrongcn.csr\n\ncsr_fields \"Self-Signed\" | \\\n${MKCERT} -key server.key -out ssigned.pem\n\n# default => T61String\ncsr_fields \"$(printf 'H%bllo World\\n' '\\0350')\" localhost |\n${REQ} -new -key server.key -out t61subj.csr\n\nSTRMASK=pkix # => BMPString\ncsr_fields \"$(printf 'H%bllo World\\n' '\\0350')\" localhost |\n${REQ} -new -key server.key -out bmpsubj.csr\n\nSTRMASK=utf8only # => UTF8String\ncsr_fields \"$(printf 'H%bllo World\\n' '\\0350')\" localhost |\n${REQ} -new -key server.key -out utf8subj.csr\n\nSTRMASK=default\n\n### produce a set of CA certs\n\ncsr_fields \"First Random CA\" \"first.example.com\" \"CAs Ltd.\" Lincoln Lincolnshire | \\\n${MKCERT} -key server.key -out ca1.pem\n\ncsr_fields \"Second Random CA\" \"second.example.com\" \"CAs Ltd.\" Falmouth Cornwall | \\\n${MKCERT} -key server.key -out ca2.pem\n\ncsr_fields \"Third Random CA\" \"third.example.com\" \"CAs Ltd.\" Ipswich Suffolk | \\\n${MKCERT} -key server.key -out ca3.pem\n\ncsr_fields \"Fourth Random CA\" \"fourth.example.com\" \"CAs Ltd.\" Norwich Norfolk | \\\n${MKCERT} -key server.key -out ca4.pem\n\ncat ca/cert.pem ca[1234].pem > calist.pem\n\ncsr_fields \"Wildcard Cert Dept\" \"*.example.com\" | \\\n${REQ} -new -key server.key -out wildcard.csr\n\ncsr_fields \"Wildcard IP Cert\" \"*.0.0.1\" | \\\n${REQ} -new -key server.key -out wildip.csr\n\ncsr_fields \"Neon Client Cert\" ignored.example.com | \\\n${REQ} -new -key client.key -out client.csr\n\ncsr_fields \"Neon Encrypted Client Cert\" ignored.example.com | \\\n${REQ} -new -key enclient.key -passin pass:foobar -out enclient.csr\n\ncsr_fields \"Neon Client Cert\" ignored.example.com | \\\n${REQ} -new -key clientdsa.key -out clientdsa.csr\n\n### requests using special DN.\n\nREQDN=reqDN.doubleCN\ncsr_fields \"Double CN Dept\" \"nohost.example.com\nlocalhost\" | ${REQ} -new -key server.key -out twocn.csr\n\nREQDN=reqDN.CNfirst\necho localhost | ${REQ} -new -key server.key -out cnfirst.csr\n\nREQDN=reqDN.missingCN\necho GB | ${REQ} -new -key server.key -out missingcn.csr\n\nREQDN=reqDN.justEmail\necho blah@example.com | ${REQ} -new -key server.key -out justmail.csr\n\n# presume AVAs will come out in least->most specific order still...\nREQDN=reqDN.twoOU\ncsr_fields \"Second OU Dept\nFirst OU Dept\" | ${REQ} -new -key server.key -out twoou.csr\n\n### don't put ${REQ} invocations after here\n\nfor f in server client clientdsa enclient twocn caseless cnfirst \\\n    t61subj bmpsubj utf8subj \\\n    missingcn justmail twoou wildcard wildip wrongcn; do\n  ${CA} -days 900 -in ${f}.csr -out ${f}.cert\ndone\n\ncat client.key client.cert > clientp.pem\ncat enclient.key enclient.cert > enclient.pem\n\n${CA} -startdate `asn1date \"2 days ago\"` -enddate `asn1date \"yesterday\"` -in expired.csr -out expired.cert\n\n${CA} -startdate `asn1date \"tomorrow\"` -enddate `asn1date \"2 days\"` -in notyet.csr -out notyet.cert\n\nfor n in 1 2 3 4 5 6 9; do\n ${CA} -extensions altExt${n} -days 900 \\\n     -in altname${n}.csr -out altname${n}.cert\ndone\n\n# Sign this CSR using the intermediary CA\nCADIR=./ca2 ${CA} -days 900 -in server.csr -out ca2server.cert\n# And create a file with the concatenation of both EE and intermediary\n# cert.\ncat ca2server.cert ca2/cert.pem > ca2server.pem\n \n# sign with expired CA\nCADIR=./ca1 ${CA} -days 3 -in server.csr -out ca1server.cert\n\n# sign with not yet valid CA\nCADIR=./ca3 ${CA} -days 3 -in server.csr -out ca3server.cert\n\nMKPKCS12=\"${OPENSSL} pkcs12 -export -passout stdin -in client.cert -inkey client.key\"\n\n# generate a PKCS12 cert from the client cert: -passOUT because it's the\n# passphrase on the OUTPUT cert, confusing...\necho foobar | ${MKPKCS12} -name \"Just A Neon Client Cert\" -out client.p12\n\n# generate a PKCS#12 cert with no password and a friendly name\necho | ${MKPKCS12} -name \"An Unencrypted Neon Client Cert\" -out unclient.p12\n\n# PKCS#12 cert with DSA key\necho | ${OPENSSL} pkcs12 -name \"An Unencrypted Neon DSA Client Cert\" \\\n    -export -passout stdin \\\n    -in clientdsa.cert -inkey clientdsa.key \\\n    -out dsaclient.p12\n\n# generate a PKCS#12 cert with no friendly name\necho | ${MKPKCS12} -out noclient.p12\n\n# generate a PKCS#12 cert with no private keys\necho | ${MKPKCS12} -nokeys -out nkclient.p12\n\n# generate a PKCS#12 cert without the cert\necho | ${MKPKCS12} -nokeys -out ncclient.p12\n\n# generate an encoded PKCS#12 cert with no private keys\necho foobar | ${MKPKCS12} -nokeys -out enkclient.p12\n\n# a PKCS#12 cert including a bundled CA cert\necho foobar | ${MKPKCS12} -certfile ca/cert.pem -name \"A Neon Client Cert With CA\" -out clientca.p12\n\n### a file containing a complete chain\n\ncat ca/cert.pem server.cert > chain.pem\n\n### NSS database initialization, for testing PKCS#11.\nCERTUTIL=@CERTUTIL@\nPK12UTIL=@PK12UTIL@\n\nif [ ${CERTUTIL} != \"notfound\" -a ${PK12UTIL} != \"notfound\" ]; then\n  rm -rf nssdb\n  mkdir nssdb\n\n  echo foobar > nssdb.pw\n\n  ${CERTUTIL} -d nssdb -N -f nssdb.pw\n  ${PK12UTIL} -d nssdb -K foobar -W '' -i unclient.p12\n\n  rm -f nssdb.pw\nfi\n"
  },
  {
    "path": "test/neon.prio",
    "content": "[overrides]\ninsecure-sig-for-cert = \n\n[priorities]\nSYSTEM=LEGACY\n"
  },
  {
    "path": "test/notvalid.pem",
    "content": "-----BEGIN CERTIFICATE-----\nMIIDODCCAuKgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBoTELMAkGA1UEBhMCR0Ix\nFzAVBgNVBAgTDkNhbWJyaWRnZXNoaXJlMRIwEAYDVQQHEwlDYW1icmlkZ2UxGjAY\nBgNVBAoTEU5lb24gSGFja2VycyBMdGQuMRUwEwYDVQQLEwxOZW9uIFFBIERlcHQx\nEjAQBgNVBAMTCWxvY2FsaG9zdDEeMBwGCSqGSIb3DQEJARYPbmVvbkB3ZWJkYXYu\nb3JnMB4XDTIzMTIyNzIwNDAyOVoXDTIzMTIyODIwNDAyOVowgaExCzAJBgNVBAYT\nAkdCMRcwFQYDVQQIEw5DYW1icmlkZ2VzaGlyZTESMBAGA1UEBxMJQ2FtYnJpZGdl\nMRowGAYDVQQKExFOZW9uIEhhY2tlcnMgTHRkLjEVMBMGA1UECxMMTmVvbiBRQSBE\nZXB0MRIwEAYDVQQDEwlsb2NhbGhvc3QxHjAcBgkqhkiG9w0BCQEWD25lb25Ad2Vi\nZGF2Lm9yZzBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQDzRU5sZ8+CWQPvPkqJw9Kl\noEgT2FqzZR9RT/qbJuRBmRphiRr0g7JOh5Mr7LXaKShedFLhGidutyKKwIZJnRht\nAgMBAAGjggEBMIH+MB0GA1UdDgQWBBRFA3ktzHSuD9uB6mJOWoElmOtknzCBzgYD\nVR0jBIHGMIHDgBRFA3ktzHSuD9uB6mJOWoElmOtkn6GBp6SBpDCBoTELMAkGA1UE\nBhMCR0IxFzAVBgNVBAgTDkNhbWJyaWRnZXNoaXJlMRIwEAYDVQQHEwlDYW1icmlk\nZ2UxGjAYBgNVBAoTEU5lb24gSGFja2VycyBMdGQuMRUwEwYDVQQLEwxOZW9uIFFB\nIERlcHQxEjAQBgNVBAMTCWxvY2FsaG9zdDEeMBwGCSqGSIb3DQEJARYPbmVvbkB3\nZWJkYXYub3JnggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADQQA80TYV\n2F4QLveuldmxGoIOq5hHGxCR6aVsdtm4PGY49R5/ObCAgdWw/JV/Tc448JAz5QvU\nahr1x9kA4Vo5NZ4q\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "test/nulca.pem",
    "content": "Certificate:\n    Data:\n        Version: 3 (0x2)\n        Serial Number:\n            ce:4e:0c:d6:f7:2b:d6:6c\n        Signature Algorithm: sha1WithRSAEncryption\n        Issuer: C=GB, ST=Berkshire, L=Newbury, O=My Company Ltd, OU=CA, CN=NULL-friendly CA\n        Validity\n            Not Before: Aug  4 06:49:34 2009 GMT\n            Not After : Aug  2 06:49:34 2019 GMT\n        Subject: C=GB, ST=Berkshire, L=Newbury, O=My Company Ltd, OU=CA, CN=NULL-friendly CA\n        Subject Public Key Info:\n            Public Key Algorithm: rsaEncryption\n            RSA Public Key: (2048 bit)\n                Modulus (2048 bit):\n                    00:ca:bc:b4:01:72:0a:f4:a3:ce:c0:04:8c:43:fd:\n                    5d:27:4f:12:38:d3:11:ef:cc:1f:10:02:ef:e2:b8:\n                    24:3c:dd:2f:bf:1f:d2:27:11:d9:51:59:d2:f7:a7:\n                    c0:3d:38:a4:ff:64:86:ef:dc:f5:95:ca:49:34:8f:\n                    46:21:00:54:04:46:a0:d7:11:a1:48:a8:bd:68:27:\n                    f9:b2:72:c0:79:28:49:bb:55:b0:19:a0:6a:6f:70:\n                    8e:8a:43:a8:a3:e7:d1:13:a0:af:38:4b:09:cb:29:\n                    ca:26:c6:0c:3c:4b:20:fd:2f:08:ca:90:c6:41:35:\n                    31:ae:db:16:09:69:99:0c:fd:d1:ce:71:44:24:4f:\n                    4a:d5:c2:e1:1b:7a:c0:e3:4f:ef:72:8c:1e:32:83:\n                    5c:bc:2e:29:f1:3e:a6:7b:be:4b:10:d5:c9:5a:5a:\n                    3b:c3:f7:c4:0a:44:f7:41:d9:e8:c7:8c:17:d8:a0:\n                    86:5e:9c:5b:19:85:96:ca:68:db:d8:dc:3b:b2:26:\n                    79:f8:b1:07:2d:c3:2c:fa:e5:51:8e:aa:da:15:5a:\n                    56:fb:dc:f3:05:90:ac:05:d1:54:3b:6d:f5:14:fa:\n                    9d:0e:85:da:e9:6f:5d:46:12:f3:02:0a:a2:fe:4b:\n                    45:b6:4e:7e:41:34:cc:ab:cc:ca:b2:4a:7f:4d:66:\n                    55:81\n                Exponent: 65537 (0x10001)\n        X509v3 extensions:\n            X509v3 Subject Key Identifier: \n                0A:69:39:5F:9D:30:04:18:08:2E:02:0E:E6:EA:9D:B2:26:F6:E2:6A\n            X509v3 Authority Key Identifier: \n                keyid:0A:69:39:5F:9D:30:04:18:08:2E:02:0E:E6:EA:9D:B2:26:F6:E2:6A\n                DirName:/C=GB/ST=Berkshire/L=Newbury/O=My Company Ltd/OU=CA/CN=NULL-friendly CA\n                serial:CE:4E:0C:D6:F7:2B:D6:6C\n\n            X509v3 Basic Constraints: \n                CA:TRUE\n    Signature Algorithm: sha1WithRSAEncryption\n        02:c9:aa:28:0b:d4:c6:34:2c:a9:b6:99:29:f9:b9:42:97:c5:\n        c0:25:0d:1c:cc:35:65:a1:03:97:0d:88:7e:69:99:48:98:4b:\n        77:f6:09:1b:e6:fc:6e:52:ab:68:d1:8d:eb:2e:51:c5:7b:94:\n        7d:b5:b9:d2:1f:9a:85:67:04:51:21:97:ec:c1:1f:92:8b:74:\n        c0:3d:69:17:c1:60:4a:b2:67:6f:47:51:ef:ca:38:d4:d2:c1:\n        4c:f8:8e:3c:ab:63:cd:84:67:1e:bf:5e:38:d0:89:f6:ee:a8:\n        2d:e6:51:72:c0:b3:ed:ca:5e:58:f7:a8:23:9c:64:dc:92:81:\n        56:e5:5e:2d:70:58:cc:f3:f1:3e:00:ff:41:9a:5f:01:28:22:\n        da:55:39:4c:c2:50:e8:27:e5:89:55:c0:b6:b2:10:28:2d:9e:\n        d6:27:b1:ec:d6:74:f8:a6:31:e9:f5:79:06:46:ab:a8:54:95:\n        8f:7e:33:45:5c:fa:32:a6:0b:2f:61:b6:0d:f9:42:66:9b:b8:\n        60:be:3d:1d:83:9d:0d:b7:04:13:4c:52:9c:e8:e1:a5:82:fd:\n        29:b0:2d:f4:f7:0a:30:a1:8d:01:cb:db:5d:dd:a4:b8:36:09:\n        84:56:a9:ea:54:80:3e:fa:18:be:13:89:c7:d4:38:1f:7f:25:\n        ad:5b:22:23\n-----BEGIN CERTIFICATE-----\nMIIERTCCAy2gAwIBAgIJAM5ODNb3K9ZsMA0GCSqGSIb3DQEBBQUAMHQxCzAJBgNV\nBAYTAkdCMRIwEAYDVQQIEwlCZXJrc2hpcmUxEDAOBgNVBAcTB05ld2J1cnkxFzAV\nBgNVBAoTDk15IENvbXBhbnkgTHRkMQswCQYDVQQLEwJDQTEZMBcGA1UEAxMQTlVM\nTC1mcmllbmRseSBDQTAeFw0wOTA4MDQwNjQ5MzRaFw0xOTA4MDIwNjQ5MzRaMHQx\nCzAJBgNVBAYTAkdCMRIwEAYDVQQIEwlCZXJrc2hpcmUxEDAOBgNVBAcTB05ld2J1\ncnkxFzAVBgNVBAoTDk15IENvbXBhbnkgTHRkMQswCQYDVQQLEwJDQTEZMBcGA1UE\nAxMQTlVMTC1mcmllbmRseSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\nggEBAMq8tAFyCvSjzsAEjEP9XSdPEjjTEe/MHxAC7+K4JDzdL78f0icR2VFZ0ven\nwD04pP9khu/c9ZXKSTSPRiEAVARGoNcRoUiovWgn+bJywHkoSbtVsBmgam9wjopD\nqKPn0ROgrzhLCcspyibGDDxLIP0vCMqQxkE1Ma7bFglpmQz90c5xRCRPStXC4Rt6\nwONP73KMHjKDXLwuKfE+pnu+SxDVyVpaO8P3xApE90HZ6MeMF9ighl6cWxmFlspo\n29jcO7ImefixBy3DLPrlUY6q2hVaVvvc8wWQrAXRVDtt9RT6nQ6F2ulvXUYS8wIK\nov5LRbZOfkE0zKvMyrJKf01mVYECAwEAAaOB2TCB1jAdBgNVHQ4EFgQUCmk5X50w\nBBgILgIO5uqdsib24mowgaYGA1UdIwSBnjCBm4AUCmk5X50wBBgILgIO5uqdsib2\n4mqheKR2MHQxCzAJBgNVBAYTAkdCMRIwEAYDVQQIEwlCZXJrc2hpcmUxEDAOBgNV\nBAcTB05ld2J1cnkxFzAVBgNVBAoTDk15IENvbXBhbnkgTHRkMQswCQYDVQQLEwJD\nQTEZMBcGA1UEAxMQTlVMTC1mcmllbmRseSBDQYIJAM5ODNb3K9ZsMAwGA1UdEwQF\nMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAALJqigL1MY0LKm2mSn5uUKXxcAlDRzM\nNWWhA5cNiH5pmUiYS3f2CRvm/G5Sq2jRjesuUcV7lH21udIfmoVnBFEhl+zBH5KL\ndMA9aRfBYEqyZ29HUe/KONTSwUz4jjyrY82EZx6/XjjQifbuqC3mUXLAs+3KXlj3\nqCOcZNySgVblXi1wWMzz8T4A/0GaXwEoItpVOUzCUOgn5YlVwLayECgtntYnsezW\ndPimMen1eQZGq6hUlY9+M0Vc+jKmCy9htg35QmabuGC+PR2DnQ23BBNMUpzo4aWC\n/SmwLfT3CjChjQHL213dpLg2CYRWqepUgD76GL4TicfUOB9/Ja1bIiM=\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "test/nulcn.pem",
    "content": "Certificate:\n    Data:\n        Version: 3 (0x2)\n        Serial Number: 1 (0x1)\n        Signature Algorithm: sha1WithRSAEncryption\n        Issuer: C=GB, ST=Berkshire, L=Newbury, O=My Company Ltd, OU=CA, CN=NULL-friendly CA\n        Validity\n            Not Before: Aug  4 07:33:43 2009 GMT\n            Not After : Aug  2 07:33:43 2019 GMT\n        Subject: CN=www.bank.com\\x00.badguy.com\n        Subject Public Key Info:\n            Public Key Algorithm: rsaEncryption\n            RSA Public Key: (2048 bit)\n                Modulus (2048 bit):\n                    00:cd:26:70:96:a9:a6:5d:3e:9c:ed:0f:08:15:5a:\n                    7c:17:25:68:68:af:13:b9:ad:41:fa:12:54:e2:84:\n                    72:7d:58:d1:e2:40:42:c1:59:ed:05:3d:aa:10:53:\n                    70:00:88:3a:77:a0:c0:56:9e:ac:7d:21:2a:71:44:\n                    51:08:bc:17:07:da:a8:a3:76:dc:51:bc:1b:8a:f6:\n                    02:1a:55:bf:46:b4:44:6b:27:5e:be:e5:17:8b:56:\n                    b2:c6:82:36:11:83:a8:bf:f7:2f:0d:17:f6:cd:47:\n                    b5:6f:2b:a6:41:b6:8d:33:5f:ea:ea:8b:b1:1a:e2:\n                    99:38:ff:59:5b:0a:a1:71:13:ca:37:3f:b9:b0:1e:\n                    91:9a:c8:93:35:0c:4a:e0:9d:f4:d2:61:c7:4e:5b:\n                    41:0a:7c:31:54:99:db:f5:65:ce:80:d3:c2:02:37:\n                    64:fd:54:12:7b:ea:ac:85:59:5c:17:e1:2e:f6:d0:\n                    a8:f2:d0:2e:94:59:2f:c2:a6:5f:da:07:de:7b:2e:\n                    14:07:ed:e4:27:24:37:9d:09:2e:b1:f9:5a:48:b9:\n                    80:24:43:e6:cb:c7:6e:35:df:d5:69:34:ff:e6:d6:\n                    9e:e8:76:66:6e:5f:59:01:3c:96:3b:ec:72:0b:3c:\n                    1e:95:0f:ce:68:13:9c:22:dd:1b:b5:44:28:50:4a:\n                    05:7f\n                Exponent: 65537 (0x10001)\n        X509v3 extensions:\n            X509v3 Basic Constraints: \n                CA:FALSE\n            Netscape Comment: \n                OpenSSL Generated Certificate\n            X509v3 Subject Key Identifier: \n                33:15:24:BE:DA:66:3A:06:8B:D9:27:34:3A:AF:62:40:E4:95:66:5D\n            X509v3 Authority Key Identifier: \n                keyid:0A:69:39:5F:9D:30:04:18:08:2E:02:0E:E6:EA:9D:B2:26:F6:E2:6A\n\n    Signature Algorithm: sha1WithRSAEncryption\n        32:65:23:1f:c8:d9:53:84:82:d0:0a:eb:14:51:24:03:bc:6c:\n        1b:2a:5a:fe:1b:f0:e8:69:0c:2b:19:86:cf:7f:32:76:d8:2b:\n        d2:cf:8b:c4:d1:b6:5b:9c:60:a3:99:2e:92:72:06:ce:de:8b:\n        d2:a2:d2:89:7c:13:a9:0b:4e:be:12:09:e5:d6:28:3a:ac:a7:\n        26:56:94:7f:13:ee:64:7d:de:94:60:75:c1:bc:55:97:d4:aa:\n        13:8e:02:d8:b0:b0:70:53:ae:18:53:ce:aa:b2:2c:85:3e:e3:\n        f3:e1:26:f3:fa:5c:ee:f8:7b:0b:c6:39:b5:04:33:5e:ae:b8:\n        5e:0e:66:cc:a8:c0:6a:0d:ec:60:c1:c5:d9:39:ea:bd:1b:8f:\n        1c:7d:16:38:b1:e8:c8:37:01:aa:4b:99:df:e4:0f:10:be:61:\n        ee:9a:cf:cd:27:05:46:00:60:d8:6a:74:08:32:3c:8b:90:01:\n        6a:07:33:0c:6c:90:db:ea:fb:6a:17:1a:76:bb:73:14:27:e1:\n        a4:7e:d5:dd:30:b1:5d:f2:0e:aa:d4:b2:d5:4c:f6:4f:91:2a:\n        07:f4:37:c1:cf:48:19:c5:fe:7e:92:96:a8:df:50:6a:31:92:\n        a3:b1:14:fe:41:cc:49:62:98:4d:ea:c5:ba:05:2d:49:c3:22:\n        72:ef:41:09\n-----BEGIN CERTIFICATE-----\nMIIDjTCCAnWgAwIBAgIBATANBgkqhkiG9w0BAQUFADB0MQswCQYDVQQGEwJHQjES\nMBAGA1UECBMJQmVya3NoaXJlMRAwDgYDVQQHEwdOZXdidXJ5MRcwFQYDVQQKEw5N\neSBDb21wYW55IEx0ZDELMAkGA1UECxMCQ0ExGTAXBgNVBAMTEE5VTEwtZnJpZW5k\nbHkgQ0EwHhcNMDkwODA0MDczMzQzWhcNMTkwODAyMDczMzQzWjAjMSEwHwYDVQQD\nExh3d3cuYmFuay5jb20ALmJhZGd1eS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IB\nDwAwggEKAoIBAQDNJnCWqaZdPpztDwgVWnwXJWhorxO5rUH6ElTihHJ9WNHiQELB\nWe0FPaoQU3AAiDp3oMBWnqx9ISpxRFEIvBcH2qijdtxRvBuK9gIaVb9GtERrJ16+\n5ReLVrLGgjYRg6i/9y8NF/bNR7VvK6ZBto0zX+rqi7Ea4pk4/1lbCqFxE8o3P7mw\nHpGayJM1DErgnfTSYcdOW0EKfDFUmdv1Zc6A08ICN2T9VBJ76qyFWVwX4S720Kjy\n0C6UWS/Cpl/aB957LhQH7eQnJDedCS6x+VpIuYAkQ+bLx24139VpNP/m1p7odmZu\nX1kBPJY77HILPB6VD85oE5wi3Ru1RChQSgV/AgMBAAGjezB5MAkGA1UdEwQCMAAw\nLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0G\nA1UdDgQWBBQzFSS+2mY6BovZJzQ6r2JA5JVmXTAfBgNVHSMEGDAWgBQKaTlfnTAE\nGAguAg7m6p2yJvbiajANBgkqhkiG9w0BAQUFAAOCAQEAMmUjH8jZU4SC0ArrFFEk\nA7xsGypa/hvw6GkMKxmGz38ydtgr0s+LxNG2W5xgo5kuknIGzt6L0qLSiXwTqQtO\nvhIJ5dYoOqynJlaUfxPuZH3elGB1wbxVl9SqE44C2LCwcFOuGFPOqrIshT7j8+Em\n8/pc7vh7C8Y5tQQzXq64Xg5mzKjAag3sYMHF2TnqvRuPHH0WOLHoyDcBqkuZ3+QP\nEL5h7prPzScFRgBg2Gp0CDI8i5ABagczDGyQ2+r7ahcadrtzFCfhpH7V3TCxXfIO\nqtSy1Uz2T5EqB/Q3wc9IGcX+fpKWqN9QajGSo7EU/kHMSWKYTerFugUtScMicu9B\nCQ==\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "test/nulsan.pem",
    "content": "Certificate:\n    Data:\n        Version: 3 (0x2)\n        Serial Number: 0 (0x0)\n        Signature Algorithm: sha1WithRSAEncryption\n        Issuer: C=GB, ST=Berkshire, L=Newbury, O=My Company Ltd, OU=CA, CN=NULL-friendly CA\n        Validity\n            Not Before: Aug  4 06:53:05 2009 GMT\n            Not After : Aug  2 06:53:05 2019 GMT\n        Subject: CN=www.badguy.com\n        Subject Public Key Info:\n            Public Key Algorithm: rsaEncryption\n            RSA Public Key: (2048 bit)\n                Modulus (2048 bit):\n                    00:cd:26:70:96:a9:a6:5d:3e:9c:ed:0f:08:15:5a:\n                    7c:17:25:68:68:af:13:b9:ad:41:fa:12:54:e2:84:\n                    72:7d:58:d1:e2:40:42:c1:59:ed:05:3d:aa:10:53:\n                    70:00:88:3a:77:a0:c0:56:9e:ac:7d:21:2a:71:44:\n                    51:08:bc:17:07:da:a8:a3:76:dc:51:bc:1b:8a:f6:\n                    02:1a:55:bf:46:b4:44:6b:27:5e:be:e5:17:8b:56:\n                    b2:c6:82:36:11:83:a8:bf:f7:2f:0d:17:f6:cd:47:\n                    b5:6f:2b:a6:41:b6:8d:33:5f:ea:ea:8b:b1:1a:e2:\n                    99:38:ff:59:5b:0a:a1:71:13:ca:37:3f:b9:b0:1e:\n                    91:9a:c8:93:35:0c:4a:e0:9d:f4:d2:61:c7:4e:5b:\n                    41:0a:7c:31:54:99:db:f5:65:ce:80:d3:c2:02:37:\n                    64:fd:54:12:7b:ea:ac:85:59:5c:17:e1:2e:f6:d0:\n                    a8:f2:d0:2e:94:59:2f:c2:a6:5f:da:07:de:7b:2e:\n                    14:07:ed:e4:27:24:37:9d:09:2e:b1:f9:5a:48:b9:\n                    80:24:43:e6:cb:c7:6e:35:df:d5:69:34:ff:e6:d6:\n                    9e:e8:76:66:6e:5f:59:01:3c:96:3b:ec:72:0b:3c:\n                    1e:95:0f:ce:68:13:9c:22:dd:1b:b5:44:28:50:4a:\n                    05:7f\n                Exponent: 65537 (0x10001)\n        X509v3 extensions:\n            X509v3 Basic Constraints: \n                CA:FALSE\n            Netscape Comment: \n                OpenSSL Generated Certificate\n            X509v3 Subject Key Identifier: \n                33:15:24:BE:DA:66:3A:06:8B:D9:27:34:3A:AF:62:40:E4:95:66:5D\n            X509v3 Authority Key Identifier: \n                keyid:0A:69:39:5F:9D:30:04:18:08:2E:02:0E:E6:EA:9D:B2:26:F6:E2:6A\n\n            X509v3 Subject Alternative Name: \n                DNS:www.bank.com\n    Signature Algorithm: sha1WithRSAEncryption\n        27:6e:7d:b3:a9:86:52:57:6a:a0:c6:30:6c:1e:94:09:a7:6f:\n        ad:fe:11:9f:be:32:8d:01:7b:8b:94:66:d7:7c:b6:b1:90:fc:\n        e4:f5:b6:32:bc:6c:71:23:b1:18:88:d6:47:bc:da:07:c7:5e:\n        46:71:3a:e6:40:6e:c1:7f:1d:56:96:70:65:d8:51:a9:dc:9e:\n        a5:06:00:98:e7:1e:10:bc:82:ba:00:e5:4e:a2:0f:3e:ec:8a:\n        dd:6f:c6:c9:c1:ec:ed:6d:7c:31:3e:66:87:47:a1:8b:15:3c:\n        21:7e:ec:21:78:3d:21:70:72:ba:70:c3:64:f8:1d:4f:d9:d0:\n        27:3c:3e:7e:a2:59:ae:be:9a:d3:00:44:a7:72:3a:e3:3f:c8:\n        9b:c5:8f:b1:94:fe:00:0f:6e:b8:14:88:f1:03:50:91:51:af:\n        f0:1e:f7:b8:5a:a4:57:35:2d:f1:ad:c8:ae:dd:29:61:14:7d:\n        ea:d1:34:80:5c:1b:fd:eb:43:dc:21:6d:c6:44:f9:3b:54:76:\n        c4:91:5b:ac:a4:8e:72:e7:d8:24:ff:a7:5a:c0:ef:27:c3:d7:\n        e4:f9:7f:55:8d:0d:30:ec:a2:d9:6d:c8:76:f4:be:94:3d:12:\n        32:4a:91:4f:db:c3:e7:76:07:5a:12:97:18:b7:15:00:98:59:\n        21:89:3e:35\n-----BEGIN CERTIFICATE-----\nMIIDrTCCApWgAwIBAgIBADANBgkqhkiG9w0BAQUFADB0MQswCQYDVQQGEwJHQjES\nMBAGA1UECBMJQmVya3NoaXJlMRAwDgYDVQQHEwdOZXdidXJ5MRcwFQYDVQQKEw5N\neSBDb21wYW55IEx0ZDELMAkGA1UECxMCQ0ExGTAXBgNVBAMTEE5VTEwtZnJpZW5k\nbHkgQ0EwHhcNMDkwODA0MDY1MzA1WhcNMTkwODAyMDY1MzA1WjAZMRcwFQYDVQQD\nEw53d3cuYmFkZ3V5LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\nAM0mcJappl0+nO0PCBVafBclaGivE7mtQfoSVOKEcn1Y0eJAQsFZ7QU9qhBTcACI\nOnegwFaerH0hKnFEUQi8FwfaqKN23FG8G4r2AhpVv0a0RGsnXr7lF4tWssaCNhGD\nqL/3Lw0X9s1HtW8rpkG2jTNf6uqLsRrimTj/WVsKoXETyjc/ubAekZrIkzUMSuCd\n9NJhx05bQQp8MVSZ2/VlzoDTwgI3ZP1UEnvqrIVZXBfhLvbQqPLQLpRZL8KmX9oH\n3nsuFAft5CckN50JLrH5Wki5gCRD5svHbjXf1Wk0/+bWnuh2Zm5fWQE8ljvscgs8\nHpUPzmgTnCLdG7VEKFBKBX8CAwEAAaOBpDCBoTAJBgNVHRMEAjAAMCwGCWCGSAGG\n+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQU\nMxUkvtpmOgaL2Sc0Oq9iQOSVZl0wHwYDVR0jBBgwFoAUCmk5X50wBBgILgIO5uqd\nsib24mowJgYDVR0RBB8wHYIbd3d3LmJhbmsuY29tAHd3dy5iYWRndXkuY29tMA0G\nCSqGSIb3DQEBBQUAA4IBAQAnbn2zqYZSV2qgxjBsHpQJp2+t/hGfvjKNAXuLlGbX\nfLaxkPzk9bYyvGxxI7EYiNZHvNoHx15GcTrmQG7Bfx1WlnBl2FGp3J6lBgCY5x4Q\nvIK6AOVOog8+7Irdb8bJweztbXwxPmaHR6GLFTwhfuwheD0hcHK6cMNk+B1P2dAn\nPD5+olmuvprTAESncjrjP8ibxY+xlP4AD264FIjxA1CRUa/wHve4WqRXNS3xrciu\n3SlhFH3q0TSAXBv960PcIW3GRPk7VHbEkVuspI5y59gk/6dawO8nw9fk+X9VjQ0w\n7KLZbch29L6UPRIySpFP28PndgdaEpcYtxUAmFkhiT41\n-----END CERTIFICATE-----\n"
  },
  {
    "path": "test/nulsrv.key",
    "content": "-----BEGIN RSA PRIVATE KEY-----\nMIIEogIBAAKCAQEAzSZwlqmmXT6c7Q8IFVp8FyVoaK8Tua1B+hJU4oRyfVjR4kBC\nwVntBT2qEFNwAIg6d6DAVp6sfSEqcURRCLwXB9qoo3bcUbwbivYCGlW/RrREayde\nvuUXi1ayxoI2EYOov/cvDRf2zUe1byumQbaNM1/q6ouxGuKZOP9ZWwqhcRPKNz+5\nsB6RmsiTNQxK4J300mHHTltBCnwxVJnb9WXOgNPCAjdk/VQSe+qshVlcF+Eu9tCo\n8tAulFkvwqZf2gfeey4UB+3kJyQ3nQkusflaSLmAJEPmy8duNd/VaTT/5tae6HZm\nbl9ZATyWO+xyCzwelQ/OaBOcIt0btUQoUEoFfwIDAQABAoIBAF55tl3b8O5+GDyf\nsIRM8FqkconLHtViccDdUlQi1KrfDYEZQOTUKfBA7qGoGytTkUFoOUtqtVrGvEn/\nQSY5oI2QaBsncNz/ONvs4RkJphXEjMGgFuTokcgsfBYo/wdfz4XgKr3n7FOrE2YH\n/v/CNxKSuJedD0mnUxLJnXfs1F5DAE+nE88T2LsWLqo8Jxr/6wFnazaAYmtkQd3/\nBNBn9a7K79G81e7FkRSIc+7De7iju6UMy010qY6UNyFw9hSWQgjxzxwiyFvRuu4C\nw4xRJo2z0vEL6TSnNZEpTVVAbBd8XYSjh/627uXBah8W50X4BWLOd1umgU1hJDXe\ncXIWVZkCgYEA9QXcOdOPzuQ6wQYEi7qvTKSRdUJ+D3BCbqSHyWEe4RotWqs9WV1F\nFFpaRO/aiIdqpVZE8YJlcAcKtIXBS/byKUfOFzHX2QvROmPlcavXrVtFnNsBQpIn\nhyYjs/z/vbFDgugLBKVsgEaZzlJeygbI61r2NjVnst7NzP9L8ZxFgDsCgYEA1ldI\nnZcXekaqpUAMCSdZPDcfocVUb8UjvRZf90EruWymbrJQxzym5HaX20MFFh1BKC+a\nJEexxhlbfth/zgX6Pux7fqxSJM11DBG1aik7t4GMRu1bfflpQjdQUXGn2YPI5Quz\nR6QPcXhLVLY8b8PJu2jSKjV0cDN02dFwEFv9340CgYBRpUhDBJow6KAjXav6G5T6\nRwQpPKTg5Ble4PhWREST4bMnOVRSCOBR7eGSgxIg2G7S9TI3/6lpcQ9CJCfK9liv\nJLwpwnQYYPWxLURxYj+WBonlwJxk4GrHgA/5k95sCTtjzYqOW8kR3XS26X+odiZR\nNphAa/9H/TI6kv9tXRNTrQKBgGoREVciwLR6qdFSq2IQPcFlidq02r7gsHnOy7iA\nYJHGqWmYBg9B/ViLM0SGmsrBuU+Yls+jRt7AB53ypvQd0yM2RTp/LbsWjPhm/v5E\n309E5VTn+mGRfbwNwUo8UxJ5e32U16f5EMdW/vgxoiCwo3CBQ5ctkqw/WnC7ipgd\n3bi1AoGAbJSdtaFdF0kSikqvcPEJMFBR24dT7W+JIXeuFHYbRkQGSVZLGxuAkbL5\n1mY+qclcvzfijH0wNFRP1Z3M5eFERALwI25YOrZGtI1ncIeKV+yFwkYC54XfZUvr\nhQO0wVIbTaE3N9fDIs0rHbSc1GJUhVr+2IsTW/ybHgdfDZMuXOI=\n-----END RSA PRIVATE KEY-----\n"
  },
  {
    "path": "test/oldacl.c",
    "content": "/* \n   Dummy ACL tests\n   Copyright (C) 2001-2003, Joe Orton <joe@manyfish.co.uk>\n\n   This program is free software; you can redistribute it and/or modify\n   it under the terms of the GNU General Public License as published by\n   the Free Software Foundation; either version 2 of the License, or\n   (at your option) any later version.\n  \n   This program is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU General Public License for more details.\n  \n   You should have received a copy of the GNU General Public License\n   along with this program; if not, write to the Free Software\n   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\n*/\n\n#include \"ne_acl.h\"\n\n#include \"tests.h\"\n#include \"child.h\"\n#include \"utils.h\"\n\n/**** DUMMY TESTS: just makes sure the stuff doesn't dump core. */\n\nstatic int test_acl(const char *uri, ne_acl_entry *es, int nume)\n{\n    ne_session *sess;\n\n    CALL(make_session(&sess, single_serve_string, \n\t\t      \"HTTP/1.1 200 OK\\r\\n\"\n\t\t      \"Connection: close\\r\\n\\r\\n\"));\n    \n    ON(ne_acl_set(sess, uri, es, nume));\n    \n    return destroy_and_wait(sess);\n}\n\nstatic int grant_all(void)\n{\n    ne_acl_entry e = {0};\n\n    e.apply = ne_acl_all;\n    e.type = ne_acl_grant;\n\n    CALL(test_acl(\"/foo\", &e, 1));\n\n    return OK;\n}\n\nstatic int deny_all(void)\n{\n    ne_acl_entry e = {0};\n\n    e.apply = ne_acl_all;\n    e.type = ne_acl_deny;\n    \n    CALL(test_acl(\"/foo\", &e, 1));\n\n    return OK;\n}\n\nstatic int deny_one(void)\n{\n    ne_acl_entry e = {0};\n\n    e.apply = ne_acl_href;\n    e.type = ne_acl_deny;\n    e.principal = \"http://webdav.org/users/joe\";\n\n    CALL(test_acl(\"/foo\", &e, 1));\n\n    return OK;\n}       \n\nstatic int deny_byprop(void)\n{\n    ne_acl_entry e = {0};\n\n    e.apply = ne_acl_property;\n    e.type = ne_acl_deny;\n    e.principal = \"owner\";\n\n    CALL(test_acl(\"/foo\", &e, 1));\n\n    return OK;\n}\n\nne_test tests[] = {\n    T(grant_all),\n    T(deny_all),\n    T(deny_one),\n    T(deny_byprop),\n    T(NULL)\n};\n"
  },
  {
    "path": "test/openssl.conf",
    "content": "[ca]\ndefault_ca = neonca\n\n[neonca]\ndir = ${ENV::CADIR}\ndatabase = $dir/index.txt\nnew_certs_dir = $dir\ncertificate = $dir/cert.pem\nserial = $dir/serial\nprivate_key = $dir/key.pem\npolicy = policy_any\ndefault_md = sha256\nx509_extensions = issuedExt\nunique_subject = no\ndefault_bits = 2048\n\n# same as neonca1 just +basicConstraints and without certificate to\n# allow creation of the initial self signed certificate\n[neoncainit]\ndir = ${ENV::CADIR}\ndatabase = $dir/index.txt\nnew_certs_dir = $dir\nserial = $dir/serial\nprivate_key = $dir/key.pem\npolicy = policy_any\ndefault_md = sha256\nx509_extensions = issuedExt\nunique_subject = no\nbasicConstraints = CA:TRUE\ndefault_bits = 2048\n\n[policy_any]\ncountryName = optional\nstateOrProvinceName = optional\nlocalityName = optional\norganizationName = optional\norganizationalUnitName = optional\ncommonName = optional\nemailAddress = optional\n\n[req]\ndistinguished_name = $ENV::REQDN\nx509_extensions = caExt\nstring_mask = $ENV::STRMASK\ndefault_bits = 2048\n\n[caExt]\nbasicConstraints = CA:true\n\n[issuedExt]\nbasicConstraints = CA:false\n\n# subjectAltName extension sections\n[altExt1]\nsubjectAltName = DNS:localhost\n\n# 2+3: AltNames with multiple entries to test the matching logic\n[altExt2]\nsubjectAltName = DNS:nohost.example.com, DNS:localhost\n\n[altExt3]\nsubjectAltName = DNS:localhost, DNS:nohost.example.com\n\n# an AltName with no DNS entries; should use commonName instead for\n# identity check\n[altExt4]\nsubjectAltName = email:neon@webdav.org\n\n# an AltName with IP address\n[altExt5]\nsubjectAltName = IP:127.0.0.1\n\n# an AltName with a bad IP address\n[altExt6]\nsubjectAltName = IP:1.2.3.4\n\n# AltName with wildcard\n[altExt9]\nsubjectAltName = DNS:*.example.com\n\n[reqDN]\ncountryName = Country Name\nstateOrProvinceName = State or Province Name\nlocalityName = Locality Name\norganizationName = Organization Name\norganizationalUnitName = Organizational Unit Name\ncommonName = Common Name (eg, your name or your server\\'s hostname)\nemailAddress = Email Address\n\n# a DN which gives two commonName attributes.\n[reqDN.doubleCN]\ncountryName = Country Name\nstateOrProvinceName = State or Province Name\nlocalityName = Locality Name\norganizationName = Organization Name\norganizationalUnitName = Organizational Unit Name\n0.commonName = Common Name\n1.commonName = Common Name\nemailAddress = Email Address\n\n[reqDN.twoOU]\ncountryName = Country Name\nstateOrProvinceName = State or Province Name\nlocalityName = Locality Name\norganizationName = Organization Name\n0.organizationalUnitName = Organizational Unit Name\n1.organizationalUnitName = Organizational Unit Name\ncommonName = Common Name (eg, your name or your server\\'s hostname)\nemailAddress = Email Address\n\n[reqDN.CNfirst]\ncommonName = Common Name\n\n[reqDN.missingCN]\ncountryName = CountryName\n\n[reqDN.justEmail]\nemailAddress = CountryName\n"
  },
  {
    "path": "test/props.c",
    "content": "/* \n   Tests for property handling\n   Copyright (C) 2002-2009, Joe Orton <joe@manyfish.co.uk>\n\n   This program is free software; you can redistribute it and/or modify\n   it under the terms of the GNU General Public License as published by\n   the Free Software Foundation; either version 2 of the License, or\n   (at your option) any later version.\n  \n   This program is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU General Public License for more details.\n  \n   You should have received a copy of the GNU General Public License\n   along with this program; if not, write to the Free Software\n   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\n*/\n\n#include \"config.h\"\n\n#include <sys/types.h>\n\n#ifdef HAVE_STDLIB_H\n#include <stdlib.h>\n#endif\n#ifdef HAVE_UNISTD_H\n#include <unistd.h>\n#endif\n\n#include \"ne_props.h\"\n\n#include \"tests.h\"\n#include \"child.h\"\n#include \"utils.h\"\n\nstatic const ne_propname p_alpha = {\"DAV:\", \"alpha\"},\n    p_beta = {\"http://webdav.org/random/namespace\", \"beta\"};\n\n/* Tests little except that ne_proppatch() doesn't segfault. */\nstatic int patch_simple(void)\n{\n    ne_session *sess;\n    ne_proppatch_operation ops[] = {\n\t{ &p_alpha, ne_propset, \"fish\" },\n\t{ &p_beta, ne_propremove, NULL },\n\t{ NULL, ne_propset, NULL }\n    };\n    \n    CALL(make_session(&sess, single_serve_string, \n\t\t      \"HTTP/1.1 200 Goferit\\r\\n\"\n\t\t      \"Connection: close\\r\\n\\r\\n\"));\n    ONREQ(ne_proppatch(sess, \"/fish\", ops));\n\n    return destroy_and_wait(sess);\n}\n\n#define RESP207 \"HTTP/1.0 207 Stuff\\r\\n\" \"Content-Type: text/xml\\r\\n\" \"Server: foo\\r\\n\\r\\n\"\n\nstatic void dummy_results(void *ud, const ne_uri *uri,\n\t\t\t  const ne_prop_result_set *rset)\n{\n    NE_DEBUG(NE_DBG_HTTP, \"dummy_results.\\n\");\n}\n\n/* Regression tests for propfind bodies which caused segfaults. */\nstatic int regress(void)\n{\n    static const char *bodies[] = { \n\tRESP207 \"<?xml version=\\\"1.0\\\" encoding=\\\"utf-8\\\"?>\\n\"\n\t\"<multistatus xmlns=\\\"DAV:\\\">\"\n\t\"<response><propstat><prop><href>\"\n\t\"</href></prop></propstat></response>\"\n\t\"</multistatus>\",\n\t\n\t/* segfaults with neon <= 0.23.5 */\n\tRESP207 \"<?xml version=\\\"1.0\\\"?><D:multistatus xmlns:D=\\\"DAV:\\\">\"\n\t\"<D:response><D:href>/foo/</D:href>\"\n\t\"<D:propstat/>\"\n\t\"<D:status>HTTP/1.1 404 Not Found</D:status>\"\n\t\"</D:multistatus>\",\n\n\t/* format string handling with neon <= 0.24.4 */\n\tRESP207 \"<?xml version=\\\"1.0\\\"?><D:multistatus xmlns:D=\\\"DAV:\\\">\"\n\t\"<D:response><D:href>/foo/</D:href>\"\n\t\"<D:propstat/>\"\n\t\"<D:status>%s%s%s%s</D:status>\"\n\t\"</D:response></D:multistatus>\",\n\n\tNULL,\n    };\n    ne_session *sess;\n    int n;\n\n    for (n = 0; bodies[n] != NULL; n++) {\n\tCALL(make_session(&sess, single_serve_string, (void *)bodies[n]));\n\tne_simple_propfind(sess, \"/\", 0, NULL, dummy_results, NULL);\n\tCALL(destroy_and_wait(sess));\n    }\n\n    return OK;\n}\n\nstatic int patch_regress(void)\n{\n    static const char *bodies[] = { \n\t/* format string handling bugs with neon <= 0.24.4 */\n\tRESP207 \"<?xml version=\\\"1.0\\\"?><D:multistatus xmlns:D=\\\"DAV:\\\">\"\n\t\"<D:response><D:href>/foo/</D:href>\"\n\t\"<D:status>HTTP/1.1 500 Bad Voodoo</D:status>\"\n\t\"<D:responsedescription>%s%s%s%s</D:responsedescription>\"\n        \"</D:response></D:multistatus>\",\n\n\tRESP207 \"<?xml version=\\\"1.0\\\"?><D:multistatus xmlns:D=\\\"DAV:\\\">\"\n\t\"<D:response><D:href>/foo/</D:href>\"\n\t\"<D:status>HTTP/1.1 %s%s%s%s</D:status>\",\n\n        NULL\n    };\n    ne_session *sess;\n    int n;\n    static const ne_propname pn = { \"DAV:\", \"foobar\" };\n    ne_proppatch_operation pops[] = { \n        { &pn, ne_propset, \"fish\" },\n        { NULL, ne_propset, NULL }\n    };\n\n    for (n = 0; bodies[n] != NULL; n++) {\n\tCALL(make_session(&sess, single_serve_string, (void *)bodies[n]));\n\tne_proppatch(sess, \"/\", pops);\n\tCALL(destroy_and_wait(sess));\n    }\n\n    return OK;\n}\n\n/* Serialize propfind result callbacks into a string */\nstatic int simple_iterator(void *vbuf, const ne_propname *name,\n                           const char *value, const ne_status *st)\n{\n    char code[20];\n    ne_buffer *buf = vbuf;\n\n    ne_buffer_concat(buf, \"prop:[{\", name->nspace, \",\", \n                     name->name, \"}=\", NULL);\n    if (value)\n        ne_buffer_concat(buf, \"'\", value, \"'\", NULL);\n    else \n        ne_buffer_zappend(buf, \"#novalue#\");\n    sprintf(code, \":{%d \", st->code);\n    if (st->reason_phrase)\n        ne_buffer_concat(buf, code, st->reason_phrase, \"}];\", NULL);\n    else\n        ne_buffer_concat(buf, code, \"#noreason#}];\", NULL);\n    return 0;\n}\n\nstatic void simple_results(void *buf, const ne_uri *uri,\n                           const ne_prop_result_set *rset)\n{\n    ne_buffer_concat(buf, \"results(\", uri->path, \",\", NULL);\n    ne_propset_iterate(rset, simple_iterator, buf);\n    ne_buffer_czappend(buf, \")//\");\n}\n\n/* Test function to compare two long strings and print a digestible\n * failure message. */\nstatic int diffcmp(const char *expected, const char *actual)\n{\n    size_t n;\n    \n    if (!strcmp(expected, actual)) return OK;\n\n    NE_DEBUG(NE_DBG_HTTP, \n             \"diffcmp: Expect: [%s]\\n\"\n             \"diffcmp: Actual: [%s]\\n\",\n             expected, actual);\n\n    for (n = 0; expected[n] && actual[n]; n++) {\n        if (expected[n] != actual[n]) {\n            t_context(\"difference at byte %\" NE_FMT_SIZE_T \": \"\n                      \"`%.10s...' not `%.10s...'\",\n                      n, actual+n, expected+n);\n            break;\n        }\n    }\n\n    return FAIL;\n}\n\n/* PROPFIND creator callback. */\nstatic void *pf_creator(void *userdata, const ne_uri *uri)\n{\n    ne_buffer *buf = userdata;\n\n    NE_DEBUG(NE_DBG_HTTP, \"pf: Creator at %s\\n\", uri->path);\n\n    ne_buffer_concat(buf, \"creator[\", uri->path, \"]//\", NULL);\n\n    return ne_strdup(uri->path);\n}\n\n/* PROPFIND destructor callback. */\nstatic void pf_destructor(void *userdata, void *private)\n{\n    ne_buffer *buf = userdata;\n    char *cookie = private;\n\n    NE_DEBUG(NE_DBG_HTTP, \"pf: Destructor at %s\\n\", cookie);\n\n    ne_buffer_concat(buf, \"destructor[\", cookie, \"]//\", NULL);\n    \n    ne_free(cookie);\n}\n\n  \n/* PROPFIND test type. */     \nenum pftype { \n    PF_SIMPLE, /* using ne_simple_propfind */\n    PF_NAMED,  /* using ne_propfind_named */\n    PF_SP_NAMED, /* using ne_propfind_named w/SHAREPOINT hacks */\n    PF_ALLPROP /* using ne_propfind_allprop */\n};\n\nstatic int run_propfind(const ne_propname *props, char *resp, \n                        int depth, const char *expected, enum pftype type)\n{\n    ne_session *sess;\n    ne_buffer *buf = ne_buffer_create();\n\n    CALL(make_session(&sess, single_serve_string, resp));\n\n    if (type == PF_SIMPLE) {\n        ONREQ(ne_simple_propfind(sess, \"/propfind\", depth, props,\n                                 simple_results, buf));\n    }\n    else {\n        ne_propfind_handler *hdl;\n\n        if (type == PF_SP_NAMED) {\n            ne_set_session_flag(sess, NE_SESSFLAG_SHAREPOINT, 1);\n            type = PF_NAMED;\n        }\n\n        hdl = ne_propfind_create(sess, \"/propfind\", depth);\n\n        ne_propfind_set_private(hdl, pf_creator, pf_destructor,\n                                buf);\n        \n        if (type == PF_NAMED) {\n            ONREQ(ne_propfind_named(hdl, props, simple_results, buf));\n        }\n        else {\n            ONREQ(ne_propfind_allprop(hdl, simple_results, buf));\n        }\n\n        ne_propfind_destroy(hdl);\n    }\n\n    CALL(diffcmp(expected, buf->data));\n    ne_buffer_destroy(buf);\n\n    return destroy_and_wait(sess);\n}\n\n/* a PROPFIND response body for the {DAV:}fishbone property, using\n * given property value and status. */\n#define FISHBONE_RESP(value, status) MULTI_207(RESP_207(\"/foop\", \\\n\tPSTAT_207(PROPS_207(APROP_207(\"fishbone\", value)) \\\n\tSTAT_207(status))))\n\nstatic int propfind(void)\n{\n    static const struct {\n        char *resp;\n        const char *expected;\n        int depth;\n        enum pftype type;\n    } ts[] = {\n        /* simple single property. */\n        { FISHBONE_RESP(\"hello, world\", \"212 Well OK\"),\n          \"results(/foop,prop:[{DAV:,fishbone}='hello, world':{212 Well OK}];)//\",\n          0, PF_SIMPLE },\n        /* property with some nested elements. */\n        { FISHBONE_RESP(\"this is <foo/> a property <bar><lemon>fish</lemon></bar> value\", \n                        \"299 Just About OK\"),\n          \"results(/foop,prop:[{DAV:,fishbone}=\"\n          \"'this is <foo></foo> a property \"\n          \"<bar><lemon>fish</lemon></bar> value':\"\n          \"{299 Just About OK}];)//\",\n          0, PF_SIMPLE },\n\n        /* failed to fetch a property. */\n        { FISHBONE_RESP(\"property value is ignored\", \n                        \"404 Il n'ya pas de property\"),\n          \"results(/foop,prop:[{DAV:,fishbone}=#novalue#:\"\n          \"{404 Il n'ya pas de property}];)//\",\n          0, PF_SIMPLE },\n\n#if 0\n        /* propstat missing status should be ignored; if a response contains no\n         * valid propstats, it should also be ignored. */\n        { MULTI_207(RESP_207(\"/alpha\", PSTAT_207(APROP_207(\"fishbone\", \"unseen\")))\n                    RESP_207(\"/beta\", PSTAT_207(APROP_207(\"fishbone\", \"hello, world\")\n                                                STAT_207(\"200 OK\")))),\n          \"results(/beta,prop:[{DAV:,fishbone}='hello, world':{200 OK}];)//\", 0, \n          PF_SIMPLE },\n#endif\n\n        /* props on several resources */\n        { MULTI_207(RESP_207(\"/alpha\",\n                             PSTAT_207(PROPS_207(APROP_207(\"fishbone\", \"strike one\"))\n                                       STAT_207(\"234 First is OK\")))\n                    RESP_207(\"/beta\",\n                             PSTAT_207(PROPS_207(APROP_207(\"fishbone\", \"strike two\"))\n                                       STAT_207(\"256 Second is OK\")))),\n          \"results(/alpha,prop:[{DAV:,fishbone}='strike one':{234 First is OK}];)//\"\n          \"results(/beta,prop:[{DAV:,fishbone}='strike two':{256 Second is OK}];)//\",\n          0, PF_SIMPLE},\n\n        /* whitespace handling. */\n        { MULTI_207(RESP_207(\"\\r\\nhttp://localhost/alpha \",\n                             PSTAT_207(PROPS_207(APROP_207(\"alpha\", \"beta\"))\n                                       \"<D:status>\\r\\nHTTP/1.1 200 OK </D:status>\"))),\n          \"results(/alpha,prop:[{DAV:,alpha}='beta':{200 OK}];)//\",\n          0, PF_SIMPLE},\n        \n        /* attribute handling. */\n        { MULTI_207(RESP_207(\"\\r\\nhttp://localhost/alpha \",\n                             PSTAT_207(PROPS_207(\"<D:alpha>\"\n                                                 \"<D:foo D:fee='bar' bar='fee'>beta</D:foo></D:alpha>\")\n                                       \"<D:status>\\r\\nHTTP/1.1 200 OK </D:status>\"))),\n          \"results(/alpha,prop:[{DAV:,alpha}='<DAV:foo DAV:fee='bar' bar='fee'>beta</DAV:foo>':{200 OK}];)//\",\n          0, PF_SIMPLE},\n        \n\n        /* \"complex\" propfinds. */\n\n        { FISHBONE_RESP(\"hello, world\", \"212 Well OK\"),\n          \"creator[/foop]//\"\n          \"results(/foop,prop:[{DAV:,fishbone}='hello, world':{212 Well OK}];)//\"\n          \"destructor[/foop]//\",\n          0, PF_NAMED },\n\n        /* 207 with badly encoded URI in href */\n        { MULTI_207(RESP_207(\"http://example.com/foo€bar\", \\\n                             PSTAT_207(PROPS_207(APROP_207(\"fishbone\", \"hello, world\")) \\\n                                       STAT_207(\"209 Good News\")))),\n          \"creator[/foo%e2%82%acbar]//\"\n          \"results(/foo%e2%82%acbar,prop:[{DAV:,fishbone}='hello, world':{209 Good News}];)//\"\n          \"destructor[/foo%e2%82%acbar]//\",\n          0, PF_SP_NAMED },\n\n        { MULTI_207(RESP_207(\"/foo%20bar/€bar\", \\\n                             PSTAT_207(PROPS_207(APROP_207(\"fishbone\", \"hello, world\")) \\\n                                       STAT_207(\"209 Good News\")))),\n          \"creator[/foo%20bar/%e2%82%acbar]//\"\n          \"results(/foo%20bar/%e2%82%acbar,prop:[{DAV:,fishbone}='hello, world':{209 Good News}];)//\"\n          \"destructor[/foo%20bar/%e2%82%acbar]//\",\n          0, PF_SP_NAMED }\n\n    };\n    const ne_propname pset1[] = {\n        { \"DAV:\", \"fishbone\", },\n        { NULL, NULL }\n    };\n    unsigned n;\n\n    for (n = 0; n < sizeof(ts)/sizeof(ts[0]); n++) {\n        const ne_propname *pset = pset1;\n\n        NE_DEBUG(NE_DBG_HTTP, \"--> running test %u for %s\\n\", n, ts[n].resp);\n        CALL(run_propfind(pset, ts[n].resp, ts[n].depth,\n                          ts[n].expected, ts[n].type));\n    }\n\n\n    return OK;\n}\n\nstatic int unbounded_response(const char *header, const char *repeats)\n{\n    ne_session *sess;\n    struct infinite i = { header, repeats};\n\n    CALL(make_session(&sess, serve_infinite, &i));\n\n    ONN(\"unbounded PROPFIND response did not fail\",\n        ne_simple_propfind(sess, \"/\", 0, NULL, \n                           dummy_results, NULL) != NE_ERROR);\n\n    CALL(reap_server());    \n    ne_session_destroy(sess);\n    return OK;\n}\n\nstatic int unbounded_propstats(void)\n{\n    return unbounded_response(\n\tRESP207 \"<?xml version=\\\"1.0\\\" encoding=\\\"utf-8\\\"?>\\n\"\n\t\"<multistatus xmlns=\\\"DAV:\\\">\"\n\t\"<response><href>/</href>\",\n        \"<propstat></propstat>\");\n}\n\nstatic int unbounded_props(void)\n{\n    return unbounded_response(\n\tRESP207 \"<?xml version=\\\"1.0\\\" encoding=\\\"utf-8\\\"?>\\n\"\n\t\"<multistatus xmlns=\\\"DAV:\\\">\"\n\t\"<response><href>/</href><propstat>\",\n        \"<prop><jim>hello, world</jim></prop>\");\n}\n\nne_test tests[] = {\n    T(patch_simple),\n    T(propfind),\n    T(regress),\n    T(patch_regress),\n    T(unbounded_props),\n    T(unbounded_propstats),\n    T(NULL) \n};\n\n"
  },
  {
    "path": "test/redirect.c",
    "content": "/* \n   Tests for 3xx redirect interface (ne_redirect.h)\n   Copyright (C) 2002-2024, Joe Orton <joe@manyfish.co.uk>\n\n   This program is free software; you can redistribute it and/or modify\n   it under the terms of the GNU General Public License as published by\n   the Free Software Foundation; either version 2 of the License, or\n   (at your option) any later version.\n  \n   This program is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU General Public License for more details.\n  \n   You should have received a copy of the GNU General Public License\n   along with this program; if not, write to the Free Software\n   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\n*/\n\n#include \"config.h\"\n\n#include <sys/types.h>\n\n#ifdef HAVE_STDLIB_H\n#include <stdlib.h>\n#endif\n#ifdef HAVE_UNISTD_H\n#include <unistd.h>\n#endif\n\n#include \"ne_redirect.h\"\n\n#include \"tests.h\"\n#include \"child.h\"\n#include \"utils.h\"\n\n/* Run a request to 'path' and retrieve the redirect destination to\n * *redir. */\nstatic int process_redir(ne_session *sess, const char *path,\n                         const ne_uri **redir)\n{\n    int ret = any_request(sess, path);\n    ONV(ret != NE_REDIRECT,\n        (\"request got %d (%s) rather than NE_REDIRECT\",\n         ret, ne_get_error(sess)));\n    *redir = ne_redirect_location(sess);\n    return OK;\n}\n\nstatic int check_redir(int status_code, const char *location,\n                       const char *target, const char *fragment,\n                       const char *expect)\n{\n    char *unp, *full_expect = NULL, response[BUFSIZ];\n    ne_session *sess;\n    ne_uri *loc;\n    ne_request *req;\n\n    ne_snprintf(response, sizeof response,\n\t\t\"HTTP/1.0 %d Get Ye Away\\r\\n\"\n\t\t\"Content-Length: 0\\r\\n\"\n\t\t\"Location: %s\\r\\n\\n\",\n\t\tstatus_code, location);\n\n    CALL(multi_session_server(&sess, \"http\", 2,\n                              single_serve_string, response));\n\n    if (expect[0] == '/') {\n        ne_uri uri = {0};\n        ne_fill_server_uri(sess, &uri);\n        uri.path = (char *)expect;\n        uri.fragment = (char *)fragment;\n        full_expect = ne_uri_unparse(&uri);\n        expect = full_expect;\n        uri.path = NULL;\n        uri.fragment = NULL;\n        ne_uri_free(&uri);\n    }\n\n    /* First test the ne_get_response_location() API directly. */\n    NE_DEBUG(NE_DBG_HTTP, \"redirect: Target [%s ## %s]\\n\", target,\n             fragment ? fragment : \"(no fragment)\");\n    NE_DEBUG(NE_DBG_HTTP, \"redirect: Location: [%s]\\n\", location);\n\n    req = ne_request_create(sess, \"GET\", target);\n    ONREQ(ne_request_dispatch(req));\n    loc = ne_get_response_location(req, fragment);\n\n    unp = ne_uri_unparse(loc);\n    NE_DEBUG(NE_DBG_HTTP, \"redirect: ne_get_response_location => [%s]\\n\", unp);\n    ONV(strcmp(unp, expect), (\"first redirect to `%s' not `%s'\", unp, expect));\n    ne_free(unp);\n    ne_request_destroy(req);\n    ne_uri_free(loc);\n    ne_free(loc);\n\n    if (fragment) {\n        /* Can't handle fragments in the ne_redirect API, send a dummy request. */\n        CALL(any_request(sess, \"/dummy\"));\n    }\n    else {\n        const ne_uri *cloc;\n\n        /* Second, test the ne_redirect* API. */\n        ne_redirect_register(sess);\n\n        CALL(process_redir(sess, target, &cloc));\n        ONN(\"redirect location was NULL\", cloc == NULL);\n\n        unp = ne_uri_unparse(cloc);\n        NE_DEBUG(NE_DBG_HTTP, \"redirect: ne_redirect URI => [%s]\\n\", unp);\n        ONV(strcmp(unp, expect), (\"second redirect to `%s' not `%s'\", unp, expect));\n        ne_free(unp);\n    }\n\n    if (full_expect) ne_free(full_expect);\n\n    return destroy_and_wait(sess);\n}\n\n#define DEST \"http://foo.com/blah/blah/bar\"\n#define PATH \"/redir/me\"\n\nstatic int redirects(void)\n{\n    const struct {\n        const char *target;\n        int code;\n        const char *location;\n        const char *expected;\n        const char *fragment;\n    } ts[] = {\n        {PATH, 301, DEST, DEST, NULL},\n        {PATH, 302, DEST, DEST, NULL},\n        {PATH, 303, DEST, DEST, NULL},\n        {PATH, 307, DEST, DEST, NULL},\n\n        /* Simple relative URI cases: */\n        {PATH, 302, \"/foo/bar/blah\", \"/foo/bar/blah\", NULL},\n        {\"/foo/bar\", 302, \"norman\", \"/foo/norman\", NULL},\n        {\"/foo/bar/\", 302, \"wishbone\", \"/foo/bar/wishbone\", NULL},\n\n        /* all 3xx should get NE_REDIRECT. */\n        {PATH, 399, DEST, DEST, NULL},\n\n        /* Handling of various request-target cases. */\n        {\"*\", 307, \"/fish#food\", \"/fish#food\", NULL},\n        {\"ftp://example.com/fish\", 307, \"/fish#food\", \"ftp://example.com/fish#food\", NULL},\n\n        /* More relative URIs: */\n        {\"/blah\", 307, \"//example.com:8080/fish#food\", \"http://example.com:8080/fish#food\", NULL},\n        {\"/blah\", 307, \"#food\", \"/blah#food\", NULL},\n\n        /* Fragment handling. */\n        {\"/foo\", 301, \"http://example.com/redirect\", \"http://example.com/redirect#fragment\",\n         \"fragment\" },\n        {\"/foo\", 301, \"https://blah.example.com/redirect#override\",\n         \"https://blah.example.com/redirect#override\", \"fragment\" },\n    };\n    unsigned n;\n    \n    for (n = 0; n < sizeof(ts)/sizeof(ts[0]); n++) {\n        CALL(check_redir(ts[n].code, ts[n].location, ts[n].target, ts[n].fragment,\n                         ts[n].expected));\n    }\n\n    return OK;\n}\n\n#define RESP1 \"HTTP/1.1 200 OK\\r\\n\" \"Content-Length: 0\\r\\n\\r\\n\"\n#define RESP2 \"HTTP/1.0 302 Get Ye Away\\r\\n\" \"Location: /blah\\r\\n\" \"\\r\\n\"\n\n/* ensure that ne_redirect_location returns NULL when no redirect has\n * been encountered, or redirect hooks aren't registered. */\nstatic int no_redirect(void)\n{\n    ne_session *sess;\n    const ne_uri *loc;\n    struct double_serve_args resp;\n\n    resp.first.data = RESP1;\n    resp.first.len = strlen(RESP1);\n    resp.second.data = RESP2;\n    resp.second.len = strlen(RESP2);\n\n    CALL(session_server(&sess, double_serve_sstring, &resp));\n    ONN(\"redirect non-NULL before register\", ne_redirect_location(sess));\n    ne_redirect_register(sess);\n    ONN(\"initial redirect non-NULL\", ne_redirect_location(sess));\n\n    ONREQ(any_request(sess, \"/noredir\"));\n    ONN(\"redirect non-NULL after non-redir req\", ne_redirect_location(sess));\n\n    CALL(process_redir(sess, \"/foo\", &loc));\n    ONV(loc == NULL || strcmp(loc->path, \"/blah\"),\n        (\"redirect returned was '%s' not /blah\", loc ? loc->path : \"(null)\"));\n\n    return destroy_and_wait(sess);\n}\n\nne_test tests[] = {\n    T(lookup_localhost),\n    T(redirects),\n    T(no_redirect),\n    T(NULL) \n};\n\n"
  },
  {
    "path": "test/request.c",
    "content": "/* \n   HTTP request handling tests\n   Copyright (C) 2001-2024, Joe Orton <joe@manyfish.co.uk>\n\n   This program is free software; you can redistribute it and/or modify\n   it under the terms of the GNU General Public License as published by\n   the Free Software Foundation; either version 2 of the License, or\n   (at your option) any later version.\n  \n   This program is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU General Public License for more details.\n  \n   You should have received a copy of the GNU General Public License\n   along with this program; if not, write to the Free Software\n   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\n*/\n\n#include \"config.h\"\n\n#include <sys/types.h>\n\n#include <time.h> /* for time() */\n\n#ifdef HAVE_STDLIB_H\n#include <stdlib.h>\n#endif\n#ifdef HAVE_UNISTD_H\n#include <unistd.h>\n#endif\n#include <fcntl.h>\n#include <errno.h>\n\n#include \"ne_request.h\"\n#include \"ne_socket.h\"\n\n#include \"tests.h\"\n#include \"child.h\"\n#include \"utils.h\"\n\nstatic char buffer[BUFSIZ];\n\nstatic ne_session *def_sess;\nstatic ne_request *def_req;\n\n/* Last (real) port used by fail_request_with_error(). */\nstatic unsigned int fail_request_last_port;\n\nstatic int prepare_request(server_fn fn, void *ud)\n{\n    static char uri[100];\n\n    CALL(session_server(&def_sess, fn, ud));\n\n    sprintf(uri, \"/test%d\", test_num);\n\n    def_req = ne_request_create(def_sess, \"GET\", uri);\n\n    return OK;\n}\n\nstatic int finish_request(void)\n{\n    ne_request_destroy(def_req);\n    return destroy_and_wait(def_sess);\n}\n\n#define RESP200 \"HTTP/1.1 200 OK\\r\\n\" \"Server: neon-test-server\\r\\n\"\n#define TE_CHUNKED \"Transfer-Encoding: chunked\\r\\n\"\n#define CHUNK(len, data) #len \"\\r\\n\" data \"\\r\\n\"\n#define ABCDE_CHUNKS CHUNK(1, \"a\") CHUNK(1, \"b\") \\\n CHUNK(1, \"c\") CHUNK(1, \"d\") \\\n CHUNK(1, \"e\") CHUNK(0, \"\")\n\n/* takes response body chunks and appends them to a buffer. */\nstatic int collector(void *ud, const char *data, size_t len)\n{\n    ne_buffer *buf = ud;\n    ne_buffer_append(buf, data, len);\n    return 0;\n}\n\ntypedef ne_request *(*construct_request)(ne_session *sess, void *userdata);\n\n/* construct a get request, callback for run_request. */\nstatic ne_request *construct_get(ne_session *sess, void *userdata)\n{\n    ne_request *r = ne_request_create(sess, \"GET\", \"/\");\n    ne_buffer *buf = userdata;\n\n    if (buf) ne_add_response_body_reader(r, ne_accept_2xx, collector, buf);\n\n    return r;\n}\n\n/* run a request created by callback 'cb' in session 'sess'. */\nstatic int run_request(ne_session *sess, int status,\n\t\t       construct_request cb, void *userdata)\n{\n    ne_request *req = cb(sess, userdata);\n\n    ON(req == NULL);\n    \n    ONREQ(ne_request_dispatch(req));\n \n    ONV(ne_get_status(req)->code != status,\n\t(\"response status-code was %d not %d\",\n\t ne_get_status(req)->code, status));\n\n    ne_request_destroy(req);\n\n    return OK;\n}\n\n/* Runs a server function 'fn', expecting to get a header 'name' with\n * value 'value' in the response.  If 'value' is NULL, expects that\n * *no* header of that name is present. */\nstatic int expect_header_value(const char *name, const char *value,\n\t\t\t       server_fn fn, void *userdata)\n{\n    ne_session *sess;\n    ne_request *req;\n    const char *gotval;\n\n    CALL(make_session(&sess, fn, userdata));\n\n    NE_DEBUG(NE_DBG_HTTP, \"[test] Testing for expected header [%s] / [%s]\\n\",\n             name, value);\n\n    req = ne_request_create(sess, \"FOO\", \"/bar\");\n    ONREQ(ne_request_dispatch(req));\n    ne_close_connection(sess);\n    CALL(await_server());\n\n    if (strcmp(name, \"X-Trailer\") == 0)\n        gotval = ne_get_response_trailer(req, name);\n    else\n        gotval = ne_get_response_header(req, name);\n    ONV(value && !gotval, (\"header '%s: %s' not sent\", name, value));\n    ONV(!value && gotval, (\"header '%s: %s' not expected\", name, gotval));\n\n    ONV(value && gotval && strcmp(gotval, value),\n\t(\"header '%s' mis-match: got '%s' not '%s'\", \n         name, gotval, value));\n    \n    ne_request_destroy(req);\n    ne_session_destroy(sess);\n\n    return OK;\n}\n\n/* runs a server function 'fn', expecting response body to be equal to\n * 'expect' */\nstatic int expect_response(const char *expect, server_fn fn, void *userdata)\n{\n    ne_session *sess;\n    ne_buffer *buf = ne_buffer_create();\n\n    CALL(session_server(&sess, fn, userdata));\n    CALL(run_request(sess, 200, construct_get, buf));\n    CALL(destroy_and_wait(sess));\n\n    ONN(\"response body match\", strcmp(buf->data, expect));\n\n    ne_buffer_destroy(buf);\n    \n    return OK;\n}\n\n#define EMPTY_RESP RESP200 \"Content-Length: 0\\r\\n\\r\\n\"\n\n/* Process a request with given method and response, expecting to get\n * a zero-length response body.  A second request is sent down the\n * connection (to ensure that the response isn't silently eaten), so\n * 'resp' must be an HTTP/1.1 response with no 'Connection: close'\n * header. */\nstatic int expect_no_body(const char *method, const char *resp)\n{\n    ne_session *sess;\n    ne_request *req;\n    ssize_t ret;\n    char *r = ne_malloc(strlen(resp) + sizeof(EMPTY_RESP));\n    \n    strcpy(r, resp);\n    strcat(r, EMPTY_RESP);\n    CALL(session_server(&sess, single_serve_string, r));\n    ne_free(r);\n\n    req = ne_request_create(sess, method, \"/first\");\n    ONN(\"failed to begin request\", ne_begin_request(req));\n    ret = ne_read_response_block(req, buffer, BUFSIZ);\n    ONV(ret != 0, (\"got response block of size %\" NE_FMT_SSIZE_T, ret));\n    ONN(\"failed to end request\", ne_end_request(req));\n\n    /* process following request; makes sure that nothing extra has\n     * been eaten by the first request. */\n    ONV(any_request(sess, \"/second\"),\n\t(\"second request on connection failed: %s\",ne_get_error(sess)));\n\n    ne_request_destroy(req);\n\n    return destroy_and_wait(sess);\n}\n\nstatic int reason_phrase(void)\n{\n    ne_session *sess;\n\n    CALL(make_session(&sess, single_serve_string, RESP200\n\t\t      \"Connection: close\\r\\n\\r\\n\"));\n    ONREQ(any_request(sess, \"/foo\"));\n    ne_close_connection(sess);\n    CALL(await_server());\n    \n    ONV(strcmp(ne_get_error(sess), \"200 OK\"),\n\t(\"reason phrase mismatch: got `%s' not `200 OK'\",\n\t ne_get_error(sess)));\n\n    ne_session_destroy(sess);\n    return OK;    \n}\n\n#if 0\n/* This feature was added then remoevd, it potentially wasn't safe\n * since the location string wasn't cleaned or checked to be a valid\n * URI. */\nstatic int redirect_error(void)\n{\n    ne_session *sess;\n\n    CALL(make_session(&sess, single_serve_string,\n                      \"HTTP/1.1 301 Moved Permanently\\r\\n\"\n                      \"Location: http://example.com/redirected\\r\\n\"\n\t\t      \"Connection: close\\r\\n\\r\\n\"));\n    ONREQ(any_request(sess, \"/foo\"));\n    ne_close_connection(sess);\n    CALL(await_server());\n\n    ONV(strcmp(ne_get_error(sess), \"Redirected to http://example.com/redirected\"),\n\t(\"error mismatch: got `%s' not redirect location\",\n\t ne_get_error(sess)));\n\n    ne_session_destroy(sess);\n    return OK;\n}\n#endif\n\nstatic int no_body_304(void)\n{\n    return expect_no_body(\"GET\", \"HTTP/1.1 304 Not Mfodified\\r\\n\"\n\t\t\t  \"Content-Length: 5\\r\\n\\r\\n\");\n}\n\nstatic int no_body_204(void)\n{\n    return expect_no_body(\"GET\", \"HTTP/1.1 204 Not Modified\\r\\n\"\n\t\t\t  \"Content-Length: 5\\r\\n\\r\\n\");\n}\n\nstatic int no_body_HEAD(void)\n{\n    return expect_no_body(\"HEAD\", \"HTTP/1.1 200 OK\\r\\n\"\n\t\t\t  \"Content-Length: 5\\r\\n\\r\\n\");\n}\n\nstatic int chunk_oversize(void)\n{\n#define BIG (20000)\n    char *body = ne_malloc(BIG + 1);\n    static const char rnd[] = \"abcdefghijklm\";\n    int n;\n    ne_buffer *buf = ne_buffer_create();\n    \n    for (n = 0; n < BIG; n++) {\n\tbody[n] = rnd[n % (sizeof(rnd) - 1)];\n    }\n    body[n] = '\\0';\n#undef BIG\n\n    ne_buffer_concat(buf, RESP200 TE_CHUNKED \"\\r\\n\" \n\t\t     \"4E20\\r\\n\", body, \"\\r\\n\",\n\t\t     \"0\\r\\n\\r\\n\", NULL);\n\n    CALL(expect_response(body, single_serve_string, buf->data));\n    \n    ne_buffer_destroy(buf);\n    ne_free(body);\n\n    return OK;\n}\n\n/* obscure case which is possibly a valid request by 2616, but should\n * be handled correctly in any case.  neon <0.22.0 tries to \n * eat the response body, which is probably incorrect. */\nstatic int no_body_chunks(void)\n{\n    return expect_no_body(\"HEAD\", \"HTTP/1.1 204 Not Modified\\r\\n\"\n\t\t\t  TE_CHUNKED \"\\r\\n\");\n}\n\nstatic int serve_twice(ne_socket *sock, void *userdata)\n{\n    const char *resp = userdata;\n    \n    CALL(discard_request(sock));\n    SEND_STRING(sock, resp);\n\n    CALL(discard_request(sock));\n    SEND_STRING(sock, resp);\n\n    return OK;\n}\n\n/* Test persistent connection handling: serve 'response' twice on a\n * single TCP connection, expecting to get a response body equal to\n * 'body' both times. */\nstatic int test_persist_p(const char *response, const char *body, int proxy)\n{\n    ne_session *sess;\n    ne_buffer *buf = ne_buffer_create();\n\n    if (proxy) {\n        CALL(proxied_session_server(&sess, \"http\", \"localhost\", 1234,\n                                    serve_twice, (void *)response));\n        ne_set_session_flag(sess, NE_SESSFLAG_CONNAUTH, 1);\n    }\n    else {\n        CALL(session_server(&sess, serve_twice, (void *)response));\n    }\n\n    CALL(run_request(sess, 200, construct_get, buf));\n    \n    ONV(strcmp(buf->data, body),\n\t(\"response #1 mismatch: [%s] not [%s]\", buf->data, body));\n\n    /* Run it again. */\n    ne_buffer_clear(buf);\n    CALL(run_request(sess, 200, construct_get, buf));\n    CALL(destroy_and_wait(sess));\n\n    ONV(strcmp(buf->data, body),\n\t(\"response #2 mismatch: [%s] not [%s]\", buf->data, body));\n\n    ne_buffer_destroy(buf);\n\n    return OK;\n}\n\nstatic int test_persist(const char *response, const char *body)\n{\n    return test_persist_p(response, body, 0);\n}\n\nstatic int persist_http11(void)\n{\n    return test_persist(RESP200 \"Content-Length: 5\\r\\n\\r\\n\" \"abcde\",\n\t\t\t\"abcde\");\n}\n\nstatic int persist_chunked(void)\n{\n    return test_persist(RESP200 TE_CHUNKED \"\\r\\n\" ABCDE_CHUNKS,\n\t\t\t\"abcde\");\n}\n\nstatic int persist_http10(void)\n{\n    return test_persist(\"HTTP/1.0 200 OK\\r\\n\"\n\t\t\t\"Connection: keep-alive\\r\\n\"\n\t\t\t\"Content-Length: 5\\r\\n\\r\\n\" \"abcde\",\n\t\t\t\"abcde\");\n}\n\nstatic int persist_proxy_http10(void)\n{\n    return test_persist_p(\"HTTP/1.0 200 OK\\r\\n\"\n                          \"Proxy-Connection: keep-alive\\r\\n\"\n                          \"Content-Length: 5\\r\\n\\r\\n\" \"abcde\",\n                          \"abcde\", 1);\n}\n\n/* Server function for fail_early_eof */\nstatic int serve_eof(ne_socket *sock, void *ud)\n{\n    const char *resp = ud;\n\n    /* dummy request/response. */\n    CALL(discard_request(sock));\n    CALL(SEND_STRING(sock, RESP200 \"Content-Length: 0\\r\\n\\r\\n\"));\n    /* real request/response. */\n    CALL(discard_request(sock));\n    CALL(SEND_STRING(sock, resp));\n\n    return OK;\n}\n\n/* Utility function: 'resp' is a truncated response; such that an EOF\n * arrives early during response processing; but NOT as a valid\n * premature EOF due to a persistent connection timeout.  It is an\n * error if the request is then retried, and the test fails. */\nstatic int fail_early_eof(const char *resp)\n{\n    ne_session *sess;\n\n    CALL(multi_session_server(&sess, \"http\", 3, serve_eof, (char *)resp));\n    \n    ONREQ(any_request(sess, \"/foo\"));\n    ONN(\"request retried after early EOF\",\n\tany_request(sess, \"/foobar\") == NE_OK);\n    \n    CALL(reap_server());\n    ne_session_destroy(sess);\n    return OK;\n}\n\n/* This failed with neon <0.22. */\nstatic int fail_eof_continued(void)\n{\n    return fail_early_eof(\"HTTP/1.1 100 OK\\r\\n\\r\\n\");\n}\n\nstatic int fail_eof_headers(void)\n{\n    return fail_early_eof(\"HTTP/1.1 200 OK\\r\\nJimbob\\r\\n\");\n}\n\nstatic int fail_eof_chunk(void)\n{\n    return fail_early_eof(RESP200 TE_CHUNKED \"\\r\\n\" \"1\\r\\n\" \"a\");\n}\n\nstatic int fail_eof_badclen(void)\n{\n    return fail_early_eof(RESP200 \"Content-Length: 10\\r\\n\\r\\n\" \"abcde\");\n}\n\n/* Persistent connection timeout where a FIN is sent to terminate the\n * connection, which is caught by a 0 return from the read() when the\n * second request reads the status-line. */\nstatic int ptimeout_eof(void)\n{\n    ne_session *sess;\n\n    CALL(multi_session_server(&sess, \"http\", 4, single_serve_string, \n                              RESP200 \"Content-Length: 0\\r\\n\" \"\\r\\n\"));\n    \n    CALL(any_2xx_request(sess, \"/first\"));\n    CALL(any_2xx_request(sess, \"/second\"));\n    \n    ONN(\"server died prematurely?\", dead_server());\n    reap_server();\n\n    ne_session_destroy(sess);\n    return OK;\n}\n\n/* Persistent connection timeout where a FIN is sent to terminate the\n * connection, but the request fails in the write() call which sends\n * the body. */\nstatic int ptimeout_eof2(void)\n{\n    ne_session *sess;\n\n    CALL(multi_session_server(&sess, \"http\", 4, single_serve_string, \n                              RESP200 \"Content-Length: 0\\r\\n\" \"\\r\\n\"));\n\n    CALL(any_2xx_request(sess, \"/first\"));\n    minisleep();\n    CALL(any_2xx_request_body(sess, \"/second\"));\n    \n    ONN(\"server died prematurely?\", dead_server());\n    reap_server();\n\n    ne_session_destroy(sess);\n    return OK;\n}\n\n/* TODO: add a ptimeout_reset too, if an RST can be reliably generated\n * mid-connection. */\n\nstatic int incr_server(ne_socket *sock, void *arg)\n{\n    struct many_serve_args *msa = arg;\n    \n    CALL(many_serve_string(sock, msa));\n    \n    msa->count++;\n    \n    return OK;\n}\n\n/* Emulates a persistent connection timeout on the server. This tests\n * the timeout occurring after between 1 and 10 requests down the\n * connection. */\nstatic int persist_timeout(void)\n{\n    ne_session *sess;\n    ne_buffer *buf = ne_buffer_create();\n    struct many_serve_args args;\n    int n;\n\n    args.str = RESP200 \"Content-Length: 5\\r\\n\\r\\n\" \"abcde\";\n    args.count = 1;\n\n    CALL(multi_session_server(&sess, \"http\", 9, incr_server, &args));\n\n    for (args.count = 1; args.count < 10; args.count++) {\n\n\tfor (n = 0; n < args.count; n++) {\n\t    ONV(run_request(sess, 200, construct_get, buf),\n\t\t(\"%d of %d, request failed: %s\", n, args.count,\n\t\t ne_get_error(sess)));\n\t    \n\t    ONV(strcmp(buf->data, \"abcde\"),\n\t\t(\"%d of %d, response body mismatch\", n, args.count));\n\n\t    /* Ready for next time. */\n\t    ne_buffer_clear(buf);\n\t}\n    }\n\n    ne_buffer_destroy(buf);\n\n    return destroy_and_wait(sess);\n}   \n\n/* Test that an HTTP/1.0 server is not presumed to support persistent\n * connections by default. */\nstatic int no_persist_http10(void)\n{\n    ne_session *sess;\n\n    CALL(multi_session_server(&sess, \"http\", 4, single_serve_string,\n                              \"HTTP/1.0 200 OK\\r\\n\"\n                              \"Content-Length: 5\\r\\n\\r\\n\"\n                              \"abcde\"\n                              \"Hello, world - what a nice day!\\r\\n\"));\n\n    /* if the connection is treated as persistent, the status-line for\n     * the second request will be \"Hello, world...\", which will\n     * fail. */\n\n    ONREQ(any_request(sess, \"/foobar\"));\n    ONREQ(any_request(sess, \"/foobar\"));\n\n    ONN(\"server died prematurely?\", dead_server());\n    CALL(reap_server());\n    ne_session_destroy(sess);\n    return OK;\n}\n\n#define NO_BODY \"Content-Length: 0\\r\\n\\r\\n\"\n\nstatic int response_bodies(void)\n{\n    struct {\n        const char *expect;\n        server_fn fn;\n        const char *response;\n    } ts[] = {\n        { \"a\", single_serve_string, RESP200 \"Connection: close\\r\\n\" \"\\r\\n\" \"a\" },\n        { \"a\", single_serve_string, RESP200 \"Content-Length: \\t\\t 1 \\t\\t\\r\\n\"\n          \"\\r\\n\" \"a\" \"bbbbbbbbasdasd\" },\n        { \"a\", single_serve_string, RESP200 TE_CHUNKED \"\\r\\n\"\n\t\t\t   \"1\\r\\n\" \"a\\r\\n\"\n\t\t\t   \"0\\r\\n\" \"\\r\\n\"\n          \"g;lkjalskdjalksjd\" },\n        { \"abcde\", single_serve_string, \"HTTP/1.1 200 OK\\r\\n\\r\\n\" \"abcde\" }, /* no headers */\n        { \"abcde\", single_serve_string, RESP200 \"Stupid Header\\r\\n\" \"ReallyStupidHeader\\r\\n\"\n          \"Content-Length: 5\\r\\n\" \"\\r\\n\" \"abcde\" },\n        { \"abcde\", single_serve_string, RESP200 \"Content-Length: \\r\\n   5\\r\\n\" \"\\r\\n\" \"abcde\" },\n        { \"abcde\", single_serve_string, RESP200 \"Content-Length: \\r\\n \\r\\n \\r\\n \\r\\n  5\\r\\n\" \"\\r\\n\" \"abcde\" },\n        /* chunk tests */\n        { \"abcde\", single_serve_string, RESP200 TE_CHUNKED \"\\r\\n\" ABCDE_CHUNKS },\n        { \"abcde\", single_serve_string, RESP200 \"Transfer-Encoding: CHUNKED\\r\\n\" \"\\r\\n\" ABCDE_CHUNKS },\n        /* http://bugzilla.gnome.org/show_bug.cgi?id=310636 says privoxy\n         * uses the \"identity\" transfer-coding. */\n        { \"abcde\", single_serve_string, RESP200 \"Transfer-Encoding: identity\\r\\n\" \"Content-Length: 5\\r\\n\"\n          \"\\r\\n\" \"abcde\" },\n        /* leading zero's */\n        { \"0123456789abcdef\", single_serve_string, RESP200 TE_CHUNKED \"\\r\\n\"\n          \"000000010\\r\\n\" \"0123456789abcdef\\r\\n\"\n          \"000000000\\r\\n\" \"\\r\\n\" },\n        /* chunk-extensions. */\n        { \"0123456789abcdef\", single_serve_string, RESP200 TE_CHUNKED \"\\r\\n\"\n          \"000000010; foo=bar; norm=fish\\r\\n\"\n          \"0123456789abcdef\\r\\n\"\n          \"000000000\\r\\n\" \"\\r\\n\" },\n        { \"0123456789abcdef\", single_serve_string, RESP200 TE_CHUNKED \"\\r\\n\"\n          \"10 \\t ; foo=bar\\r\\n\"\n          \"0123456789abcdef\\r\\n\"\n          \"000000000\\r\\n\" \"\\r\\n\" },\n            /* trailers. */\n        { \"abcde\", single_serve_string, RESP200 TE_CHUNKED \"\\r\\n\"\n          \"00000005; foo=bar; norm=fish\\r\\n\"\n          \"abcde\\r\\n\"\n          \"000000000\\r\\n\"\n          \"X-Hello: world\\r\\n\"\n          \"X-Another: header\\r\\n\"\n          \"\\r\\n\" },\n        /* T-E dominates over C-L. */\n        { \"abcde\", single_serve_string, RESP200 TE_CHUNKED\n          \"Content-Length: 300\\r\\n\"\n          \"\\r\\n\" ABCDE_CHUNKS },\n        { \"abcde\", single_serve_string, RESP200 \"Content-Length: 300\\r\\n\"\n          TE_CHUNKED \"\\r\\n\" ABCDE_CHUNKS },\n        { NULL, NULL, NULL }\n    };\n    unsigned n;\n\n    for (n = 0; ts[n].expect != NULL; n++ ){\n        CALL(expect_response(ts[n].expect, ts[n].fn, (void *)ts[n].response));\n    }\n\n    return OK;\n}\n\nstatic int response_headers(void)\n{\n    struct {\n        const char *name, *value;\n        server_fn fn;\n        const char *response;\n    } ts[] = {\n        { \"ranDom-HEader\", \"\", single_serve_string,      RESP200 \"RANDom-HeADEr:\\r\\n\" NO_BODY },\n        { \"ranDom-HEader\", \"noddy\", single_serve_string, RESP200 \"RANDom-HeADEr: noddy\\r\\n\" NO_BODY },\n        { \"ranDom-HEader\", \"fishy\", single_serve_string, RESP200 \"RANDom-HeADEr:    fishy\\r\\n\" NO_BODY },\n        { \"ranDom-HEader\", \"fishy\", single_serve_string, RESP200 \"RANDom-HeADEr: \\t    fishy\\r\\n\" NO_BODY},\n        { \"ranDom-HEader\", \"fishy\", single_serve_string, RESP200 \"RANDom-HeADEr: fishy  \\r\\n\" NO_BODY },\n        { \"ranDom-HEader\", \"geezer\", single_serve_string, RESP200 \"RANDom-HeADEr: \\t \\tgeezer\\r\\n\" NO_BODY },\n        { \"hello\", \"w o r l d\", single_serve_string,\n          RESP200 \"Hello:  \\n\\tw\\r\\n\\to r l\\r\\n\\td  \\r\\n\" NO_BODY },\n        { \"X-Header\", \"jim, jab, jar\", single_serve_string,\n          RESP200 \"X-Header: jim\\r\\n\" \"x-header: jab\\r\\n\" \"x-Header: jar\\r\\n\" NO_BODY },\n        { \"X-Header\", \"jim, jab, jar\", single_serve_string,\n          RESP200 \"X-Header: jim  \\r\\n\" \"x-header: jab  \\r\\n\" \"x-Header: jar  \\r\\n\" NO_BODY },\n        /* RFC 2616 14.10: headers listed in Connection must be stripped on\n         * receiving an HTTP/1.0 message in case there was a pre-1.1 proxy\n         * somewhere. */\n        { \"X-Widget\", NULL, single_serve_string,\n          \"HTTP/1.0 200 OK\\r\\n\" \"Connection: x-widget\\r\\n\" \"x-widget: blah\\r\\n\" NO_BODY },\n        { \"X-Widget\", NULL, single_serve_string,\n          \"HTTP/1.0 200 OK\\r\\n\" \"Connection: connection, x-fish, x-widget\\r\\n\" \"x-widget: blah\\r\\n\" NO_BODY },\n        /* Test trailer header handling. */\n        { \"X-Trailer\", \"foo\", single_serve_string,\n          RESP200 TE_CHUNKED \"X-Header: bar\\r\\n\\r\\n\"\n          CHUNK(6, \"foobar\") \"0\\r\\nX-Trailer: foo\\r\\n\\r\\n\" },\n        { \"X-Header\", \"foo\", single_serve_string,\n          RESP200 TE_CHUNKED \"X-Header: foo\\r\\n\\r\\n\"\n          CHUNK(6, \"foobar\") \"0\\r\\nX-Trailer: barish\\r\\n\\r\\n\" },\n        /* Test retrieving trailers. */\n        { \"X-Trailer\", \"barish\", single_serve_string,\n          RESP200 TE_CHUNKED \"X-Trailer: fooish\\r\\n\\r\\n\"\n          CHUNK(6, \"foobar\") \"0\\r\\nX-Trailer: barish\\r\\n\\r\\n\" },\n        { \"X-Trailer\", \"fishing\", single_serve_string,\n          RESP200 TE_CHUNKED \"\\r\\n0\\r\\n\" \"Hello: world\\r\\n\" \"X-Trailer: fishing\\r\\n\" \"\\r\\n\" },\n        { \"X-Trailer\", \"fish, food\", single_serve_string,\n          RESP200 TE_CHUNKED \"\\r\\n0\\r\\n\" \"Hello: world\\r\\n\"\n          \"X-Trailer: fish\\r\\n\" \"X-Trailer: food\\r\\n\\r\\n\" },\n        /* Test that bare LFs are treated as a spaces. */\n        { \"X-Test\", \"just plain spaces\", single_serve_string,\n          RESP200 \"X-Test: just\\rplain\\rspaces\\r\\n\" NO_BODY },\n        /* Invalid vs valid header names */\n        { \"Content\\\"Length\", NULL, single_serve_string,\n          RESP200 \"Content\\\"Length: foobar\\r\\n\" NO_BODY },\n        { \"Content!Length\", \"foobar\", single_serve_string,\n          RESP200 \"Content!Length: foobar\\r\\n\" NO_BODY },\n\n        { NULL, NULL, NULL, NULL }\n    };\n    unsigned n;\n\n    for (n = 0; ts[n].name != NULL; n++ )\n        CALL(expect_header_value(ts[n].name, ts[n].value, ts[n].fn, (void *)ts[n].response));\n\n    return OK;\n}\n\n/* MUST from https://www.rfc-editor.org/rfc/rfc9110.html#section-5.5-5 */\nstatic int response_header_nul(void)\n{\n    static const char response[] = RESP200 \"Nul-Buffer: foo\\0bar\\rbaz\\r\\n\"\n        TE_CHUNKED \"\\r\\n\" ABCDE_CHUNKS;\n    struct string resp;\n\n    resp.data = (char *)response;\n    resp.len = sizeof response - 1;\n\n    return expect_header_value(\"Nul-Buffer\", \"foo bar baz\", serve_sstring, &resp);\n}\n\nstatic int post_send_retry(ne_request *req, void *userdata, \n                           const ne_status *status)\n{\n    return status->code == 400 ? NE_RETRY : NE_OK;    \n}\n\n/* Test that the stored response headers are forgotten if the request\n * is retried. */\nstatic int reset_headers(void)\n{\n    ne_session *sess;\n    ne_request *req;\n    const char *value;\n\n    CALL(make_session(&sess, single_serve_string,\n                      \"HTTP/1.1 400 Hit me again\\r\\n\"\n                      \"Content-Length: 0\\r\\n\"\n                      \"X-Foo: bar\\r\\n\" \"\\r\\n\"\n\n                      \"HTTP/1.1 200 Thank you kindly\\r\\n\"\n                      \"Content-Length: 0\\r\\n\"\n                      \"X-Foo: hello fair world\\r\\n\" \"\\r\\n\"));\n\n    ne_hook_post_send(sess, post_send_retry, NULL);\n    \n    req = ne_request_create(sess, \"GET\", \"/foo\");\n\n    ONREQ(ne_request_dispatch(req));\n\n    value = ne_get_response_header(req, \"X-Foo\");\n    ONCMP(\"hello fair world\", value, \"response header\", \"X-Foo\");\n\n    ne_request_destroy(req);\n\n    return destroy_and_wait(sess);\n}\n\nstatic int iterate_none(void)\n{\n    ne_session *sess;\n    ne_request *req;\n\n    CALL(make_session(&sess, single_serve_string,\n                      \"HTTP/1.0 200 OK\\r\\n\\r\\n\"));\n\n    req = ne_request_create(sess, \"GET\", \"/\");\n    ONREQ(ne_request_dispatch(req));\n\n    ONN(\"iterator was not NULL for no headers\",\n        ne_response_header_iterate(req, NULL, NULL, NULL) != NULL);\n    ONN(\"trailer iterator was not NULL for no headers\",\n        ne_response_trailer_iterate(req, NULL, NULL, NULL) != NULL);\n\n    ne_request_destroy(req);\n\n    return destroy_and_wait(sess);\n}\n\n#define MANY_HEADERS (90)\n\ntypedef void *request_iterator(ne_request *r, void *c, const char **n, const char **v);\n\nstatic int iterate_test(int trailer, request_iterator *iterator)\n{\n    ne_request *req;\n    ne_buffer *buf = ne_buffer_create();\n    ne_session *sess;\n    int n;\n    struct header {\n        char name[10], value[10];\n        int seen;\n    } hdrs[MANY_HEADERS];\n    void *cursor = NULL;\n    const char *name, *value;\n\n    ne_buffer_czappend(buf, \"HTTP/1.0 200 OK\\r\\n\");\n\n    if (trailer) ne_buffer_czappend(buf, TE_CHUNKED \"\\r\\n\"\n                                     \"0\\r\\n\");\n\n    for (n = 0; n < MANY_HEADERS; n++) {\n        sprintf(hdrs[n].name, \"x-%d\", n);\n        sprintf(hdrs[n].value, \"Y-%d\", n);\n        hdrs[n].seen = 0;\n        \n        ne_buffer_concat(buf, hdrs[n].name, \": \", hdrs[n].value, \"\\r\\n\", NULL);\n    }\n\n    ne_buffer_czappend(buf, \"\\r\\n\");\n\n    CALL(make_session(&sess, single_serve_string, buf->data));\n\n    req = ne_request_create(sess, \"GET\", \"/foo\");\n    ONREQ(ne_request_dispatch(req));\n\n    while ((cursor = iterator(req, cursor, &name, &value))) {\n        ONV(strncmp(name, \"x-\", 2) || strncmp(value, \"Y-\", 2)\n            || strcmp(name + 2, value + 2)\n            || (n = atoi(name + 2)) >= MANY_HEADERS\n            || n < 0,\n            (\"bad name/value pair: %s = %s\", name, value));\n\n        NE_DEBUG(NE_DBG_HTTP, \"iterate: got pair (%d): %s = %s\\n\",\n                 n, name, value);\n\n        ONV(hdrs[n].seen == 1, (\"duplicate pair %d\", n));\n        hdrs[n].seen = 1;\n    }\n           \n    for (n = 0; n < MANY_HEADERS; n++) {\n        ONV(hdrs[n].seen == 0, (\"unseen pair %d\", n));\n    }\n    \n    ne_buffer_destroy(buf);\n    ne_request_destroy(req);\n\n    return destroy_and_wait(sess);\n}\n\nstatic int iterate_many(void)\n{\n    CALL(iterate_test(0, ne_response_header_iterate));\n    return iterate_test(1, ne_response_trailer_iterate);\n}\n\nstruct s1xx_args {\n    int count;\n    int hdrs;\n};\n\nstatic int serve_1xx(ne_socket *sock, void *ud)\n{\n    struct s1xx_args *args = ud;\n    CALL(discard_request(sock));\n    \n    do {\n\tif (args->hdrs) {\n\t    SEND_STRING(sock, \"HTTP/1.1 100 Continue\\r\\n\"\n\t\t\t\"Random: header\\r\\n\"\n\t\t\t\"Another: header\\r\\n\\r\\n\");\n\t} else {\n\t    SEND_STRING(sock, \"HTTP/1.1 100 Continue\\r\\n\\r\\n\");\n\t}\n    } while (--args->count > 0);\n    \n    SEND_STRING(sock, RESP200 \"Content-Length: 0\\r\\n\\r\\n\");\n    \n    return OK;\n}\n\n#define sess def_sess\n\nstatic int skip_interim_1xx(void)\n{\n    struct s1xx_args args = {0, 0};\n    ON(prepare_request(serve_1xx, &args));\n    ONREQ(ne_request_dispatch(def_req));\n    return finish_request();\n}\n\nstatic int skip_many_1xx(void)\n{\n    struct s1xx_args args = {5, 0};\n    ON(prepare_request(serve_1xx, &args));\n    ONREQ(ne_request_dispatch(def_req));\n    return finish_request();\n}\n\nstatic int skip_1xx_hdrs(void)\n{\n    struct s1xx_args args = {5, 5};\n    ON(prepare_request(serve_1xx, &args));\n    ONREQ(ne_request_dispatch(def_req));\n    return finish_request();\n}\n\n#undef sess\n\n/* server for expect_100_once: serves a 100-continue request, and\n * fails if the request body is sent twice. */\nstatic int serve_100_once(ne_socket *sock, void *ud)\n{\n    struct s1xx_args args = {2, 0};\n    char ch;\n    CALL(serve_1xx(sock, &args));\n    CALL(discard_body(sock));\n    ONN(\"body was served twice\", ne_sock_read(sock, &ch, 1) == 1);\n    return OK;\n}\n\n/* regression test; fails with neon <0.22, where the request body was\n * served *every* time a 1xx response was received, rather than just\n * once. */\nstatic int expect_100_once(void)\n{\n    ne_session *sess;\n    ne_request *req;\n    char body[BUFSIZ];\n\n    CALL(make_session(&sess, serve_100_once, NULL));\n\n    req = ne_request_create(sess, \"GET\", \"/foo\");\n    ne_set_request_flag(req, NE_REQFLAG_EXPECT100, 1);\n    ONN(\"expect100 flag ignored\",\n        ne_get_request_flag(req, NE_REQFLAG_EXPECT100) != 1);\n    memset(body, 'A', sizeof(body));\n    ne_set_request_body_buffer(req, body, sizeof(body));\n    ONREQ(ne_request_dispatch(req));\n    ne_request_destroy(req);\n\n    return destroy_and_wait(sess);\n}\n\n/* regression test for enabling 100-continue without sending a body. */\nstatic int expect_100_nobody(void)\n{\n    ne_session *sess;\n    ne_request *req;\n\n    CALL(make_session(&sess, serve_100_once, NULL));\n    \n    req = ne_request_create(sess, \"GET\", \"/foo\");\n    ne_set_request_flag(req, NE_REQFLAG_EXPECT100, 1);\n    ONREQ(ne_request_dispatch(req));\n    ne_request_destroy(req);\n\n    return destroy_and_wait(sess);\n}\n\nstruct body {\n    char *body;\n    size_t size;\n};\n\nstatic int want_body(ne_socket *sock, void *userdata)\n{\n    struct body *b = userdata;\n    char *buf = ne_malloc(b->size);\n\n    clength = 0;\n    CALL(discard_request(sock));\n    ONN(\"request has c-l header\", clength == 0);\n    \n    ONN(\"request length\", clength != b->size);\n    \n    NE_DEBUG(NE_DBG_HTTP, \n\t     \"reading body of %\" NE_FMT_SIZE_T \" bytes...\\n\", b->size);\n    \n    ON(ne_sock_fullread(sock, buf, b->size));\n    \n    ON(SEND_STRING(sock, RESP200 \"Content-Length: 0\\r\\n\\r\\n\"));\n\n    ON(memcmp(buf, b->body, b->size));\n    \n    ne_free(buf);\n    return OK;\n}\n\nstatic ssize_t provide_body(void *userdata, char *buf, size_t buflen)\n{\n    static const char *pnt;\n    static size_t left;\n    struct body *b = userdata;\n\n    if (buflen == 0) {\n\tpnt = b->body;\n\tleft = b->size;\n    } else {\n\tif (left < buflen) buflen = left;\n\tmemcpy(buf, pnt, buflen);\n\tleft -= buflen;\n    }\n    \n    return buflen;\n}\n\nstatic int send_bodies(void)\n{\n    unsigned int n, m;\n\n    struct body bodies[] = { \n\t{ \"abcde\", 5 }, \n\t{ \"\\0\\0\\0\\0\\0\\0\", 6 },\n\t{ NULL, 50000 },\n\t{ NULL }\n    };\n\n#define BIG 2\n    /* make the body with some cruft. */\n    bodies[BIG].body = ne_malloc(bodies[BIG].size);\n    for (n = 0; n < bodies[BIG].size; n++) {\n\tbodies[BIG].body[n] = (char)n%80;\n    }\n\n    for (m = 0; m < 2; m++) {\n\tfor (n = 0; bodies[n].body != NULL; n++) {\n\t    ne_session *sess;\n\t    ne_request *req;\n\t    \n\t    CALL(session_server(&sess, want_body, &(bodies[n])));\n\n\t    req = ne_request_create(sess, \"PUT\", \"/\");\n\t    ON(req == NULL);\n\n\t    if (m == 0) {\n\t\tne_set_request_body_buffer(req, bodies[n].body, bodies[n].size);\n\t    } else {\n\t\tne_set_request_body_provider(req, bodies[n].size, \n\t\t\t\t\t     provide_body, &bodies[n]);\n\t    }\n\n\t    ONREQ(ne_request_dispatch(req));\n\t    ne_request_destroy(req);\n\n\t    CALL(destroy_and_wait(sess));\n\t}\n    }\n\n    ne_free(bodies[BIG].body);\n    return OK;\n}\n\n/* Utility function: run a request using the given server fn, and the\n * request should fail. If 'error' is non-NULL, it must be a substring\n * of the error string. */\nstatic int fail_request_with_error(int with_body, server_fn fn, void *ud, \n                                   int forever, const char *error)\n{\n    ne_session *sess;\n    ne_request *req;\n    int ret;\n\n    CALL(multi_session_server(&sess, \"http\", forever ? 100 : 1, fn, ud));\n\n    /* Set default timeout, required by e.g. fail_excess_1xx. */\n    ne_set_read_timeout(sess, 2);\n\n    req = ne_request_create(sess, \"GET\", \"/\");\n\n    if (with_body) {\n\tstatic const char *body = \"random stuff\";\n\t\n\tne_set_request_body_buffer(req, body, strlen(body));\n    }\n\n    /* request should fail. */\n    ret = ne_request_dispatch(req);\n    ONN(\"request succeeded\", ret == NE_OK);\n\n    if (!forever) {\n\t/* reap the server, don't care what it's doing. */\n\treap_server();\n    }\n\n    NE_DEBUG(NE_DBG_HTTP, \"Response gave error `%s'\\n\", ne_get_error(sess));\n \n    ONV(error && strstr(ne_get_error(sess), error) == NULL,\n        (\"failed with error `%s', no `%s'\", ne_get_error(sess), error));\n\n    if (!forever)\n        ONV(any_request(sess, \"/fail/to/connect\") != NE_CONNECT,\n            (\"subsequent request re-used connection?\"));\n\n    ne_request_destroy(req);\n    ne_session_destroy(sess);\n\n    fail_request_last_port = get_session_port();\n   \n    return OK;    \n}\n\n/* Run a random GET request which is given 'body' as the response; the\n * request must fail, and 'error' must be found in the error\n * string. */\nstatic int invalid_response_gives_error(const char *resp, const char *error)\n{\n    return fail_request_with_error(0, single_serve_string, (void *)resp, 0, error);\n}\n\n/* Utility function: run a request using the given server fn, and the\n * request must fail. */\nstatic int fail_request(int with_body, server_fn fn, void *ud, int forever)\n{\n    return fail_request_with_error(with_body, fn, ud, forever, NULL);\n}\n\nstatic int unbounded_headers(void)\n{\n    struct infinite i = { RESP200, \"x-foo: bar\\r\\n\" };\n    return fail_request(0, serve_infinite, &i, 0);\n}\n\nstatic int blank_response(void)\n{\n    return fail_request(0, single_serve_string, \"\\r\\n\", 0);\n}\n\nstatic int serve_non_http(ne_socket *sock, void *ud)\n{\n    SEND_STRING(sock, \"Hello Mum.\\n\");\n    ne_sock_readline(sock, buffer, BUFSIZ);\n    return OK;\n}\n\n/* Test behaviour when not speaking to an HTTP server. Regression test\n * for infinite loop. */\nstatic int not_http(void)\n{\n    return fail_request(0, serve_non_http, NULL, 0);\n}\n\nstatic int unbounded_folding(void)\n{\n    struct infinite i = { \"HTTP/1.0 200 OK\\r\\nFoo: bar\\r\\n\", \n                          \"  hello there.\\r\\n\" };\n    return fail_request(0, serve_infinite, &i, 0);\n}\n\nstatic int serve_close(ne_socket *sock, void *ud)\n{\n    /* do nothing; the socket will be closed. */\n    return 0;\n}\n\n/* Returns non-zero if port is alive. */\nstatic int is_alive(int port)\n{\n    ne_sock_addr *addr;\n    ne_socket *sock = ne_sock_create();\n    const ne_inet_addr *ia;\n    int connected = 0;\n\n    addr = ne_addr_resolve(\"localhost\", 0);\n    for (ia = ne_addr_first(addr); ia && !connected; ia = ne_addr_next(addr))\n\tconnected = ne_sock_connect(sock, ia, port) == 0;\n    ne_addr_destroy(addr);\n    if (sock == NULL)\n\treturn 0;\n    else {\n\tne_sock_close(sock);\n\treturn 1;\n    }\n}\n\n/* This is a regression test for neon 0.17.0 and earlier, which goes\n * into an infinite loop if a request with a body is sent to a server\n * which simply closes the connection. */\nstatic int closed_connection(void)\n{\n    int ret;\n\n    /* This spawns a server process which will run the 'serve_close'\n     * response function 200 times, then die. This guarantees that the\n     * request eventually fails... */\n    CALL(fail_request(1, serve_close, NULL, 1));\n    /* if server died -> infinite loop was detected. */\n    ret = !is_alive(fail_request_last_port);\n    reap_server();\n    ONN(\"server aborted, infinite loop?\", ret);\n    return OK;\n}\n\nstatic int serve_close2(ne_socket *sock, void *userdata)\n{\n    int *count = userdata;\n    *count += 1;\n    if (*count == 1)\n\treturn 0;\n    NE_DEBUG(NE_DBG_HTTP, \"Re-entered! Buggy client.\\n\");\n    CALL(discard_request(sock));\n    CALL(SEND_STRING(sock, RESP200 \"Content-Length: 0\\r\\n\\r\\n\"));\n    return 0;\n}\n\n/* As closed_connection(); but check that the client doesn't retry\n * after receiving the EOF on the first request down a new\n * connection.  */\nstatic int close_not_retried(void)\n{\n    int count = 0;\n    ne_session *sess;\n    unsigned int port;\n    CALL(new_spawn_server(3, serve_close2, &count, &port));\n    sess = ne_session_create(\"http\", \"localhost\", port);\n    ONN(\"request was retried after EOF\", any_request(sess, \"/foo\") == NE_OK);\n    reap_server();\n    ne_session_destroy(sess);\n    return OK;\n}\n\nstatic enum {\n    prog_error, /* error */\n    prog_transfer, /* doing a transfer */\n    prog_done /* finished. */\n} prog_state = prog_transfer;\n\nstatic ne_off_t prog_last = -1, prog_total;\n\n#define FOFF \"%\" NE_FMT_NE_OFF_T\n\n/* callback for send_progress. */\nstatic void s_progress(void *userdata, ne_off_t prog, ne_off_t total)\n{\n    NE_DEBUG(NE_DBG_HTTP, \n\t     \"progress callback: \" FOFF \"/\" FOFF \".\\n\",\n\t     prog, total);\n\n    switch (prog_state) {\n    case prog_error:\n    case prog_done:\n\treturn;\n    case prog_transfer:\n\tif (total != prog_total) {\n\t    t_context(\"total unexpected: \" FOFF \" not \" FOFF \"\", total, prog_total);\n\t    prog_state = prog_error;\n\t}\n\telse if (prog > total) {\n\t    t_context(\"first progress was invalid (\" FOFF \"/\" FOFF \")\", prog, total);\n\t    prog_state = prog_error;\n\t}\n\telse if (prog_last != -1 && prog_last > prog) {\n\t    t_context(\"progress went backwards: \" FOFF \" to \" FOFF, prog_last, prog);\n\t    prog_state = prog_error;\n\t}\n\telse if (prog_last == prog) {\n\t    t_context(\"no progress made! \" FOFF \" to \" FOFF, prog_last, prog);\n\t    prog_state = prog_error;\n\t}\n\telse if (prog == total) {\n\t    prog_state = prog_done;\n\t}\n\tbreak;\n    }\n\t    \n    prog_last = prog;\n}\n\n#undef FOFF\n\nstatic ssize_t provide_progress(void *userdata, char *buf, size_t bufsiz)\n{\n    int *count = userdata;\n\n    if (*count >= 0 && buf != NULL) {\n\tbuf[0] = 'a';\n\t*count -= 1;\n\treturn 1;\n    } else {\n\treturn 0;\n    }\n}\n\nstatic int send_progress(void)\n{\n    static int count = 200;\n\n    ON(prepare_request(single_serve_string, \n\t\t       RESP200 \"Connection: close\\r\\n\\r\\n\"));\n\n    prog_total = 200;\n\n    ne_set_progress(def_sess, s_progress, NULL);\n    ne_set_request_body_provider(def_req, count,\n\t\t\t\t provide_progress, &count);\n\n#define sess def_sess\n    ONREQ(ne_request_dispatch(def_req));\n#undef sess\n    \n    ON(finish_request());\n\n    CALL(prog_state == prog_error);\n\n    return OK;    \n}\n\nstatic int read_timeout(void)\n{\n    ne_session *sess;\n    ne_request *req;\n    time_t start, finish;\n    int ret;\n\n    CALL(make_session(&sess, sleepy_server, NULL));\n    \n    /* timeout after one second. */\n    ne_set_read_timeout(sess, 1);\n    \n    req = ne_request_create(sess, \"GET\", \"/timeout\");\n\n    time(&start);\n    ret = ne_request_dispatch(req);\n    time(&finish);\n\n    reap_server();\n\n    ONN(\"request succeeded, should have timed out\", ret == NE_OK);\n    ONV(ret != NE_TIMEOUT,\n\t(\"request failed non-timeout error: %s\", ne_get_error(sess)));\n    ONN(\"timeout ignored, or very slow machine\", finish - start > 3);\n\n    ne_request_destroy(req);\n    ne_session_destroy(sess);\n\n    return OK;    \n}\n\n/* expect failure code 'code', for request to given hostname and port,\n * without running a server. */\nstatic int fail_noserver(const char *hostname, unsigned int port, int code)\n{\n     ne_session *sess = ne_session_create(\"http\", hostname, port);\n     int ret = any_request(sess, \"/foo\");\n     ne_session_destroy(sess);\n\n     ONV(ret == NE_OK,\n\t (\"request to server at %s:%u succeeded?!\", hostname, port));\n     ONV(ret != code, (\"request failed with %d not %d\", ret, code));\n\n     return OK;\n}\n\nstatic int fail_lookup(void)\n{\n    return fail_noserver(\"no.such.domain\", 4242, NE_LOOKUP);\n}\n\n/* neon 0.23.0 to 0.23.3: if a nameserver lookup failed, subsequent\n * requests on the session would crash. */\nstatic int fail_double_lookup(void)\n{\n     ne_session *sess = ne_session_create(\"http\", \"nonesuch.invalid\", 80);\n     ONN(\"request did not give lookup failure\",\n\t any_request(sess, \"/foo\") != NE_LOOKUP);\n     ONN(\"second request did not give lookup failure\",\n\t any_request(sess, \"/bar\") != NE_LOOKUP);\n     ne_session_destroy(sess);\n     return OK;\n}\n\nstatic int fail_connect(void)\n{\n    return fail_noserver(\"localhost\", 32767, NE_CONNECT);\n}\n\n/* Test that the origin server hostname is NOT resolved for a proxied\n * request. */\nstatic int proxy_no_resolve(void)\n{\n    ne_session *sess;\n    int ret;\n    \n    CALL(proxied_session_server(&sess, \"http\", \"no.such.server.invalid\", 80,\n                                single_serve_string,\n                                RESP200 \"Content-Length: 0\\r\\n\\r\\n\"));\n    \n    ret = any_request(sess, \"/foo\");\n    \n    ONN(\"origin server name resolved when proxy used\", ret == NE_LOOKUP);\n    \n    return destroy_and_wait(sess);\n}\n\n/* If the chunk size is entirely invalid, the request should be\n * aborted.  Fails with neon <0.22; invalid chunk sizes would be\n * silently treated as 'zero'. */\nstatic int fail_chunksize(void)\n{\n    return fail_request(0, single_serve_string,\n\t\t\tRESP200 TE_CHUNKED \"\\r\\n\" \"ZZZZZ\\r\\n\\r\\n\", 0);\n}\n\n/* in neon <0.22, if an error occcurred whilst reading the response\n * body, the connection would not be closed (though this test will\n * succeed in neon <0.22 since it the previous test fails). */\nstatic int abort_respbody(void)\n{\n    ne_session *sess;\n    \n    CALL(make_session(&sess, single_serve_string,\n\t\t      RESP200 TE_CHUNKED \"\\r\\n\"\n\t\t      \"zzz\\r\\n\"\n\t\t      RESP200 \"Content-Length: 0\\r\\n\\r\\n\"));\n    \n    /* connection must be aborted on the first request, since it\n     * contains an invalid chunk size. */\n    ONN(\"invalid chunk size was accepted?\",\n\tany_request(sess, \"/foo\") != NE_ERROR);\n    ne_close_connection(sess);\n    CALL(await_server());\n    \n    /* second request should fail since server has gone away. */\n    ONN(\"connection was not aborted\", any_request(sess, \"/foo\") == NE_OK);\n\n    ne_session_destroy(sess);\n    return OK;\n}\n\nstatic int serve_then_abort(ne_socket *sock, void *ud)\n{\n    int *flag = ud;\n\n    if (*flag == 1) {\n        CALL(single_serve_string(sock, \n                                 RESP200 \"Content-Length: 0\\r\\n\\r\\n\"\n                                 RESP200 TE_CHUNKED \"\\r\\n\"\n                                 \"zzzzz\\r\\n\"));\n        *flag = 0;\n    }\n\n    exit(0);\n}\n\n/* Test that after an aborted request on a persistent connection, a\n * failure of the *subsequent* request is not treated as a persistent\n * connection timeout and retried.  */\nstatic int retry_after_abort(void)\n{\n    ne_session *sess;\n    int flag = 1;\n    \n    /* Serve two responses down a single persistent connection, the\n     * second of which is invalid and will cause the request to be\n     * aborted. */\n    CALL(make_session(&sess, serve_then_abort, &flag));\n\n    ONREQ(any_request(sess, \"/first\"));\n    ONN(\"second request should fail\", any_request(sess, \"/second\") == NE_OK);\n    ne_close_connection(sess);\n    CALL(await_server());\n\n    /* A third attempt to connect to the server should fail to\n     * connect, though this is racy since someone else might come \n     * along and steal the port... oh well. */\n    ONN(\"third request was retried\",\n\tany_request(sess, \"/third\") != NE_CONNECT);\n\n    ne_session_destroy(sess);    \n    return OK;\n}\n\n/* Fail to parse the response status line: check the error message is\n * sane.  Failed during 0.23-dev briefly, and possibly with 0.22.0\n * too. */\nstatic int fail_statusline(void)\n{\n    ne_session *sess;\n    int ret;\n\n    CALL(make_session(&sess, single_serve_string, \"Fish.\\r\\n\"));\n    \n    ret = any_request(sess, \"/fail\");\n    ONV(ret != NE_ERROR, (\"request failed with %d not NE_ERROR\", ret));\n    ne_close_connection(sess);\n    ONV(strstr(ne_get_error(sess), \n               \"Could not parse response status line\") == NULL,\n\t(\"session error was `%s'\", ne_get_error(sess)));\n\n    ne_session_destroy(sess);\n    return OK;    \n}\n\n#define LEN (9000)\nstatic int fail_long_header(void)\n{\n    char resp[LEN + 500] = \"HTTP/1.1 200 OK\\r\\n\"\n\t\"Server: fish\\r\\n\";\n    size_t len = strlen(resp);\n    \n    /* add a long header */\n    memset(resp + len, 'a', LEN);\n    resp[len + LEN] = '\\0';\n    \n    strcat(resp, \"\\r\\n\\r\\n\");\n\n    return invalid_response_gives_error(resp, \"Line too long\");\n}\n\n#define VALID_ABCDE \"abcde\\r\\n\" CHUNK(0, \"\")\n\nstatic int fail_on_invalid(void)\n{\n    static const struct {\n        const char *resp, *error;\n    } ts[] = {\n        /* non-chunked TE. */\n        { RESP200 \"transfer-encoding: punked\\r\\n\" \"\\r\\n\" ABCDE_CHUNKS ,\n          \"Unknown transfer-coding\" },\n        /* chunk without trailing CRLF */\n        { RESP200 TE_CHUNKED \"\\r\\n\" \"5\\r\\n\" \"abcdeFISH\", \n          \"delimiter was invalid\" },\n        /* chunk with CR then EOF */\n        { RESP200 TE_CHUNKED \"\\r\\n\" \"5\\r\\n\" \"abcde\\n\",\n          \"not read chunk delimiter\" },\n        /* chunk with CR then notLF */\n        { RESP200 TE_CHUNKED \"\\r\\n\" \"5\\r\\n\" \"abcde\\rZZZ\",\n          \"delimiter was invalid\" },\n        /* chunk with CR then notLF */\n        { RESP200 TE_CHUNKED \"\\r\\n\" \"5\\r\\n\" \"abcde\\r\\r\\n\",\n          \"delimiter was invalid\" },\n        /* chunk with non-hex character */\n        { RESP200 TE_CHUNKED \"\\r\\n\" \"5Z\\r\\n\" \"abcde\",\n          \"Could not parse chunk size\" },\n        /* chunk size overflow */\n        { RESP200 TE_CHUNKED \"\\r\\n\" \"800000000\\r\\n\" \"abcde\\r\\n\",\n          \"Could not parse chunk size\" },\n        { RESP200 TE_CHUNKED \"\\r\\n\" \"-8000\\r\\n\" \"abcde\\r\\n\",\n          \"Could not parse chunk size\" },\n        { RESP200 TE_CHUNKED \"\\r\\n\" \"0x5\\r\\n\" VALID_ABCDE,\n          \"Could not parse chunk size\" },\n        { RESP200 TE_CHUNKED \"\\r\\n\" \"0X5\\r\\n\" VALID_ABCDE,\n          \"Could not parse chunk size\" },\n        { RESP200 TE_CHUNKED \"\\r\\n\" \"+5\\r\\n\" VALID_ABCDE,\n          \"Could not parse chunk size\" },\n        { RESP200 TE_CHUNKED \"\\r\\n\" \"5 5\\r\\n\" VALID_ABCDE,\n          \"Could not parse chunk size\" },\n        /* LF rather than CRLF in chunk-size is invalid. */\n        { RESP200 TE_CHUNKED \"\\r\\n\" \"5\\n\" VALID_ABCDE,\n          \"Invalid chunk-size line\" },\n        { RESP200 TE_CHUNKED \"\\r\\n\" \";5\\r\\n\" VALID_ABCDE,\n          \"Could not parse chunk size\" },\n        /* EOF at chunk size */\n        { RESP200 TE_CHUNKED \"\\r\\n\", \"Could not read chunk size\" },\n\n        /* negative C-L */\n        { RESP200 \"Content-Length: -1\\r\\n\" \"\\r\\n\" \"abcde\",\n          \"Invalid Content-Length\" },\n\n        /* invalid C-Ls */\n        { RESP200 \"Content-Length: 5, 3\\r\\n\" \"\\r\\n\" \"abcde\",\n          \"Invalid Content-Length\" },\n        { RESP200 \"Content-Length: 5z\\r\\n\" \"\\r\\n\" \"abcde\",\n          \"Invalid Content-Length\" },\n        { RESP200 \"Content-Length: z5\\r\\n\" \"\\r\\n\" \"abcde\",\n          \"Invalid Content-Length\" },\n\n        /* stupidly-large C-L */\n        { RESP200 \"Content-Length: 99999999999999999999999999\\r\\n\" \n          \"\\r\\n\" \"abcde\",\n          \"Invalid Content-Length\" },\n        \n        /* incompatible HTTP-version */\n        { \"HTTP/2.0 200 OK\\r\\n\"\n          \"Content-Length: 0\\r\\n\\r\\n\",\n          \"Incompatible HTTP version\" },\n        { \"HTTP/0.9 200 OK\\r\\n\"\n          \"Content-Length: 0\\r\\n\\r\\n\",\n          \"Incompatible HTTP version\" },\n\n        { NULL, NULL }\n    };\n    unsigned n;\n\n    for (n = 0; ts[n].resp; n++) {\n        NE_DEBUG(NE_DBG_HTTP, \"-- fail_on_invalid - test %u\\n\", n);\n        CALL(invalid_response_gives_error(ts[n].resp, ts[n].error));\n    }\n\n    return OK;\n}\n\nstatic int versions(void)\n{\n    ne_session *sess;\n\n    CALL(make_session(&sess, single_serve_string, \n\t\t      \"HTTP/1.1 200 OK\\r\\n\"\n\t\t      \"Content-Length: 0\\r\\n\\r\\n\"\n\n\t\t      \"HTTP/1.0 200 OK\\r\\n\"\n\t\t      \"Content-Length: 0\\r\\n\\r\\n\"));\n    \n    ONREQ(any_request(sess, \"/http11\"));\n\t \n    ONN(\"did not detect HTTP/1.1 compliance\",\n\tne_version_pre_http11(sess) != 0);\n\t \n    ONREQ(any_request(sess, \"/http10\"));\n\n    ONN(\"did not detect lack of HTTP/1.1 compliance\",\n\tne_version_pre_http11(sess) == 0);\n\n    return destroy_and_wait(sess);\n}\n\nstruct cr_args {\n    const char *method, *uri;\n    int result;\n};\n\nstatic void hk_createreq(ne_request *req, void *userdata,\n\t\t\t const char *method, const char *requri)\n{\n    struct cr_args *args = userdata;\n    \n    args->result = 1; /* presume failure */\n    \n    if (strcmp(args->method, method))\n\tt_context(\"Hook got method %s not %s\", method, args->method);\n    else if (strcmp(args->uri, requri))\n\tt_context(\"Hook got Req-URI %s not %s\", requri, args->uri);\n    else\n\targs->result = 0;\n}\n\nstatic int hook_create_req(void)\n{\n    ne_session *sess;\n    struct cr_args args;\n    ne_uri uri;\n    char *u;\n\n    CALL(make_session(&sess, single_serve_string, EMPTY_RESP EMPTY_RESP));\n\n    ne_hook_create_request(sess, hk_createreq, &args);\n\n    args.method = \"GET\";\n    args.uri = \"/foo\";\n    args.result = -1;\n\n    ONREQ(any_request(sess, \"/foo\"));\n    \n    ONN(\"first hook never called\", args.result == -1);\n    if (args.result) return FAIL;\n\n    memset(&uri, 0, sizeof uri);\n    ne_fill_server_uri(sess, &uri);\n    uri.path = \"/bar\";\n\n    args.uri = u = ne_uri_unparse(&uri);\n    args.result = -1;\n\n    ne_free(uri.host);\n    ne_free(uri.scheme);\n\n    /* force use of absoluteURI in request-uri */\n    ne_session_proxy(sess, \"localhost\", 7777);\n\n    ONREQ(any_request(sess, \"/bar\"));\n    \n    ONN(\"second hook never called\", args.result == -1);\n    if (args.result) return FAIL;\n\n    ne_free(u);\n\n    return destroy_and_wait(sess);\n}\n\nstatic int serve_check_method(ne_socket *sock, void *ud)\n{\n    char *method = ud;\n    char buf[20];\n    size_t methlen = strlen(method);\n\n    if (ne_sock_read(sock, buf, methlen) != (ssize_t)methlen)\n        return -1;\n    \n    ONN(\"method corrupted\", memcmp(buf, method, methlen));\n    \n    return single_serve_string(sock, \"HTTP/1.1 204 OK\\r\\n\\r\\n\");\n}\n                             \n\n/* Test that the method string passed to ne_request_create is\n * strdup'ed. */\nstatic int dup_method(void)\n{\n    char method[] = \"FOO\";\n    ne_session *sess;\n    ne_request *req;\n\n    CALL(make_session(&sess, serve_check_method, method));\n    \n    req = ne_request_create(sess, method, \"/bar\");\n    \n    strcpy(method, \"ZZZ\");\n\n    ONREQ(ne_request_dispatch(req));\n    ne_request_destroy(req);\n\n    return destroy_and_wait(sess);\n}\n\nstatic int abortive_reader(void *userdata, const char *buf, size_t len)\n{\n    ne_session *sess = userdata;\n    if (len == 5 && strncmp(buf, \"abcde\", 5) == 0) {\n        ne_set_error(sess, \"Reader callback failed\");\n    } else {\n        ne_set_error(sess, \"Reader callback called with length %\" NE_FMT_SIZE_T,\n                     len);\n    }\n    return NE_ERROR;\n}\n\nstatic int abort_reader(void)\n{\n    ne_session *sess;\n    ne_request *req;\n    int ret;\n\n    CALL(make_session(&sess, single_serve_string, \n                      RESP200 \"Content-Length: 5\\r\\n\\r\\n\"\n                      \"abcde\"\n                      \"HTTP/1.1 200 OK\\r\\n\"\n                      \"Content-Length: 0\\r\\n\\r\\n\"));\n\n    req = ne_request_create(sess, \"GET\", \"/foo\");\n    ne_add_response_body_reader(req, ne_accept_2xx, abortive_reader, sess);\n    ret = ne_request_dispatch(req);\n    ONV(ret != NE_ERROR, (\"request did not fail with NE_ERROR: %d\", ret));\n    ONV(strcmp(ne_get_error(sess), \"Reader callback failed\") != 0,\n        (\"unexpected session error string: %s\", ne_get_error(sess)));\n    ne_request_destroy(req);\n    /* test that the connection was closed. */\n    ONN(\"connection not closed after aborted response\",\n        any_2xx_request(sess, \"/failmeplease\") == OK);\n\n    return destroy_and_wait(sess);\n}\n\n/* attempt and fail to send request from offset 500 of /dev/null. */\nstatic int send_bad_offset(void)\n{\n    ne_session *sess;\n    ne_request *req;\n    int ret, fds[2];\n\n    CALL(make_session(&sess, single_serve_string,\n                      RESP200 \"Content-Length: 0\\r\\n\" \"\\r\\n\"));\n\n    /* create a pipe, on which seek is guaranteed to fail. */\n    ONN(\"could not create pipe\", pipe(fds) != 0);\n\n    req = ne_request_create(sess, \"PUT\", \"/null\");\n\n    ne_set_request_body_fd(req, fds[0], 500, 5);\n    \n    ret = ne_request_dispatch(req);\n\n    close(fds[0]);\n    close(fds[1]);\n\n    ONN(\"request dispatched with bad offset!\", ret == NE_OK);\n    ONV(ret != NE_ERROR,\n        (\"request failed with unexpected error code %d: %s\", \n         ret, ne_get_error(sess)));\n\n    ONV(strstr(ne_get_error(sess), \"Could not seek\") == NULL,\n        (\"bad error message from seek failure: %s\", ne_get_error(sess)));\n\n    reap_server();\n    ne_request_destroy(req);\n    ne_session_destroy(sess);\n    return OK;\n}\n\nstatic void thook_create_req(ne_request *req, void *userdata,\n                             const char *method, const char *requri)\n{\n    ne_buffer *buf = userdata;\n\n    ne_buffer_concat(buf, \"(create,\", method, \",\", requri, \")\\n\", NULL);\n}\n\nstatic void hook_pre_send(ne_request *req, void *userdata, \n                          ne_buffer *header)\n{\n    ne_buffer *buf = userdata;\n\n    ne_buffer_czappend(buf, \"(pre-send)\\n\");\n}\n\n/* Returns a static string giving a comma-separated representation of\n * the status structure passed in. */ \nstatic char *status_to_string(const ne_status *status)\n{\n    static char sbuf[128];\n\n    ne_snprintf(sbuf, sizeof sbuf, \"HTTP/%d.%d,%d,%s\", \n                status->major_version, status->minor_version,\n                status->code, status->reason_phrase);\n\n    return sbuf;\n}\n\nstatic void hook_post_headers(ne_request *req, void *userdata,\n\t\t\t      const ne_status *status)\n{\n    ne_buffer *buf = userdata;\n\n    ne_buffer_concat(buf, \"(post-headers,\", status_to_string(status), \")\\n\",\n\t\t     NULL);\n}\n\n\nstatic int hook_post_send(ne_request *req, void *userdata,\n                          const ne_status *status)\n{\n    ne_buffer *buf = userdata;\n\n    ne_buffer_concat(buf, \"(post-send,\", status_to_string(status), \")\\n\", \n\t\t     NULL);\n\n    return NE_OK;\n}\n\nstatic void hook_destroy_req(ne_request *req, void *userdata)\n{\n    ne_buffer *buf = userdata;\n\n    ne_buffer_czappend(buf, \"(destroy-req)\\n\");\n}\n\nstatic void hook_destroy_sess(void *userdata)\n{\n    ne_buffer *buf = userdata;\n\n    ne_buffer_czappend(buf, \"(destroy-sess)\\n\");\n}\n\nstatic void hook_close_conn(void *userdata)\n{\n    ne_buffer *buf = userdata;\n\n    ne_buffer_czappend(buf, \"(close-conn)\\n\");\n}\n\nstatic int hooks(void)\n{\n    ne_buffer *buf = ne_buffer_create();\n    ne_session *sess;\n    struct many_serve_args args;\n\n    args.str = RESP200 \"Content-Length: 0\\r\\n\" \"\\r\\n\";\n    args.count = 3;\n\n    CALL(make_session(&sess, many_serve_string, &args));\n\n    ne_hook_create_request(sess, thook_create_req, buf);\n    ne_hook_pre_send(sess, hook_pre_send, buf);\n    ne_hook_post_headers(sess, hook_post_headers, buf);\n    ne_hook_post_send(sess, hook_post_send, buf);\n    ne_hook_destroy_request(sess, hook_destroy_req, buf);\n    ne_hook_destroy_session(sess, hook_destroy_sess, buf);\n    ne_hook_close_conn(sess, hook_close_conn, buf);\n\n    CALL(any_2xx_request(sess, \"/first\"));\n\n    ONCMP(\"(create,GET,/first)\\n\"\n          \"(pre-send)\\n\"\n          \"(post-headers,HTTP/1.1,200,OK)\\n\"\n          \"(post-send,HTTP/1.1,200,OK)\\n\"\n          \"(destroy-req)\\n\", buf->data, \"hook ordering\", \"first result\");\n\n    ne_buffer_clear(buf);\n\n    /* Unhook for mismatched fn/ud pointers: */\n    ne_unhook_create_request(sess, hk_createreq, buf);\n    ne_unhook_create_request(sess, thook_create_req, sess);\n\n    /* Unhook real functions. */\n    ne_unhook_pre_send(sess, hook_pre_send, buf);\n    ne_unhook_destroy_request(sess, hook_destroy_req, buf);\n    ne_unhook_post_headers(sess, hook_post_headers, buf);\n\n    CALL(any_2xx_request(sess, \"/second\"));\n\n    ONCMP(\"(create,GET,/second)\\n\"\n          \"(post-send,HTTP/1.1,200,OK)\\n\", \n          buf->data, \"hook ordering\", \"second result\");\n\n    ne_buffer_clear(buf);\n\n    /* Double hook create, double hook then double unhook post. */\n    ne_hook_create_request(sess, thook_create_req, buf);\n    ne_hook_post_send(sess, hook_post_send, buf);\n    ne_unhook_post_send(sess, hook_post_send, buf);\n    ne_unhook_post_send(sess, hook_post_send, buf);\n\n    CALL(any_2xx_request(sess, \"/third\"));\n\n    ONCMP(\"(create,GET,/third)\\n\"\n          \"(create,GET,/third)\\n\", \n          buf->data, \"hook ordering\", \"third result\");\n\n    ne_buffer_clear(buf);\n\n    ne_session_destroy(sess);\n    CALL(await_server());\n\n    ONCMP(\"(destroy-sess)\\n\"\n          \"(close-conn)\\n\", buf->data, \"hook ordering\", \"first destroyed session\");\n\n    ne_buffer_clear(buf);\n\n    sess = ne_session_create(\"http\", \"www.example.com\", 80);\n    ne_hook_destroy_session(sess, hook_destroy_sess, buf);\n    ne_unhook_destroy_session(sess, hook_destroy_sess, buf);\n    ne_session_destroy(sess);\n\n    ONCMP(\"\", buf->data, \"hook ordering\", \"second destroyed session\");\n\n    ne_buffer_destroy(buf);\n\n    return OK;\n}\n\nstatic void hook_self_destroy_req(ne_request *req, void *userdata)\n{\n    ne_unhook_destroy_request(ne_get_session(req), \n                              hook_self_destroy_req, userdata);\n}\n\n/* Test that it's safe to call ne_unhook_destroy_request from a\n * destroy_request hook. */\nstatic int hook_self_destroy(void)\n{\n    ne_session *sess = ne_session_create(\"http\", \"localhost\", 1234);\n    \n    ne_hook_destroy_request(sess, hook_self_destroy_req, NULL);\n\n    ne_request_destroy(ne_request_create(sess, \"GET\", \"/\"));\n\n    ne_session_destroy(sess);\n\n    return OK;\n}\n\nstatic int icy_protocol(void)\n{\n    ne_session *sess;\n    \n    CALL(make_session(&sess, single_serve_string,\n                      \"ICY 200 OK\\r\\n\"\n                      \"Content-Length: 0\\r\\n\\r\\n\"));\n\n    ne_set_session_flag(sess, NE_SESSFLAG_ICYPROTO, 1);\n    \n    ONREQ(any_request(sess, \"/foo\"));\n\n    return destroy_and_wait(sess);\n}\n\nstatic int status(void)\n{\n    ne_session *sess;\n    ne_buffer *buf = ne_buffer_create();\n    const char *host, *addr = get_lh_addr();\n    char expect[1024];\n\n    CALL(make_session(&sess, single_serve_string, RESP200\n                      \"Content-Length: 5\\r\\n\\r\\n\" \"abcde\"));\n\n    host = get_session_host();\n\n    ne_snprintf(expect, sizeof expect,\n                \"connecting(%s,%s)-\"\n                \"connected(%s)-\"\n                \"send(0,5000)-\"\n                \"send(5000,5000)-\"\n                \"recv(0,5)-\"\n                \"recv(5,5)-\"\n                \"disconnected(%s)-\",\n                host, addr, host, host);\n\n    ne_set_notifier(sess, sess_notifier, buf);\n\n    CALL(any_2xx_request_body(sess, \"/status\"));\n\n    CALL(destroy_and_wait(sess));\n\n    ONV(strcmp(expect, buf->data),\n        (\"status event sequence mismatch: got [%s] not [%s]\",\n         buf->data, expect));\n    \n    ne_buffer_destroy(buf);\n    \n    return OK;\n}\n\nstatic int status_chunked(void)\n{\n    ne_session *sess;\n    ne_buffer *buf = ne_buffer_create();\n    const char *host, *addr = get_lh_addr();\n    char expect[1024];\n\n    CALL(make_session(&sess, single_serve_string,\n                      RESP200 TE_CHUNKED \"\\r\\n\" ABCDE_CHUNKS));\n\n    host = get_session_host();\n\n    /* This sequence is not exactly guaranteed by the API, but it's\n     * what the current implementation should do. */\n    ne_snprintf(expect, sizeof expect,\n                \"connecting(%s,%s)-\"\n                \"connected(%s)-\"\n                \"send(0,5000)-\"\n                \"send(5000,5000)-\"\n                \"recv(0,-1)-\"\n                \"recv(1,-1)-\"\n                \"recv(2,-1)-\"\n                \"recv(3,-1)-\"\n                \"recv(4,-1)-\"\n                \"recv(5,-1)-\"\n                \"recv(5,5)-\"\n                \"disconnected(%s)-\",\n                host, addr, host, host);\n\n    ne_set_notifier(sess, sess_notifier, buf);\n\n    CALL(any_2xx_request_body(sess, \"/status\"));\n\n    CALL(destroy_and_wait(sess));\n    \n    ONV(strcmp(expect, buf->data),\n        (\"status event sequence mismatch: got [%s] not [%s]\",\n         buf->data, expect));\n\n    ne_buffer_destroy(buf);\n        \n    return OK;\n}\n\nstatic int local_addr(void)\n{\n    ne_session *sess;\n    ne_inet_addr *ia = get_lh_inet_addr();\n\n    CALL(make_session(&sess, single_serve_string, RESP200 \n                      \"Connection: close\\r\\n\\r\\n\"));\n\n    ne_set_localaddr(sess, ia);\n\n    ONREQ(any_request(sess, \"/foo\"));\n\n    ne_session_destroy(sess);\n    ne_iaddr_free(ia);\n\n    return reap_server();\n}\n\n/* Regression in 0.27.0, ne_set_progress(sess, NULL, NULL) should\n * register the progress callback. */\nstatic int dereg_progress(void)\n{\n    ne_session *sess;\n\n    CALL(make_session(&sess, single_serve_string, \n                      RESP200 TE_CHUNKED \"\\r\\n\" ABCDE_CHUNKS));\n\n    ne_set_progress(sess, NULL, NULL);\n\n    ONREQ(any_request(sess, \"/foo\"));\n    \n    return destroy_and_wait(sess);\n}\n\nstatic int addrlist(void)\n{\n    ne_session *sess;\n    ne_inet_addr *ia = get_lh_inet_addr();\n    const ne_inet_addr *ial[1];\n    unsigned int port;\n\n    CALL(new_spawn_server(1, single_serve_string, EMPTY_RESP, &port));\n    sess = ne_session_create(\"http\", \"www.example.com\", port);\n\n    ial[0] = ia;\n\n    ne_set_addrlist(sess, ial, 1);\n\n    CALL(any_2xx_request(sess, \"/blah\"));\n\n    ne_iaddr_free(ia);\n    \n    return destroy_and_wait(sess);\n}\n\nstatic int socks_proxy(void)\n{\n    ne_session *sess;\n    struct socks_server srv = {0};\n\n    srv.version = NE_SOCK_SOCKSV5;\n    srv.failure = fail_none;\n    srv.expect_port = 4242;\n    srv.expect_addr = NULL;\n    srv.expect_fqdn = \"socks.example.com\";\n    srv.username = \"bloggs\";\n    srv.password = \"guessme\";\n    \n    CALL(socksproxied_session_server(&sess, &srv, srv.expect_fqdn, srv.expect_port,\n                                     single_serve_string, EMPTY_RESP));\n\n    CALL(any_2xx_request(sess, \"/blee\"));\n\n    return destroy_and_wait(sess);\n}\n\nstatic int socks_v4_proxy(void)\n{\n    ne_session *sess;\n    struct socks_server srv = {0};\n\n    srv.version = NE_SOCK_SOCKSV4;\n    srv.failure = fail_none;\n    srv.expect_port = 4242;\n    srv.expect_addr = ne_iaddr_parse(\"127.0.0.1\", ne_iaddr_ipv4);\n    srv.expect_fqdn = \"localhost\";\n    srv.username = \"bloggs\";\n    srv.password = \"guessme\";\n    \n    CALL(socksproxied_session_server(&sess, &srv, srv.expect_fqdn, srv.expect_port,\n                                     single_serve_string, EMPTY_RESP));\n\n    CALL(any_2xx_request(sess, \"/blee\"));\n\n    ne_iaddr_free(srv.expect_addr);\n\n    return destroy_and_wait(sess);\n}\n\n/* Server function which serves the request body back as the response\n * body. */\nstatic int serve_mirror(ne_socket *sock, void *userdata)\n{\n    char response[1024];\n\n    CALL(discard_request(sock));\n\n    ONV(clength == 0 || clength > sizeof buffer,\n        (\"C-L out of bounds: %lu\", clength));\n\n    ONV(ne_sock_fullread(sock, buffer, clength),\n        (\"read failed: %s\", ne_sock_error(sock)));\n    \n    ne_snprintf(response, sizeof response,\n                \"HTTP/1.0 200 OK\\r\\n\"\n                \"Content-Length: %lu\\r\\n\"\n                \"\\r\\n\", clength);\n\n    ONN(\"send response header failed\",\n        server_send(sock, response, strlen(response)));\n    \n    ONN(\"send response body failed\",\n        server_send(sock, buffer, clength));\n\n    ONV(ne_sock_read(sock, buffer, 1) != NE_SOCK_CLOSED,\n        (\"client sent data after request: %c\", buffer[0]));\n\n    return OK;\n}\n\n/* Test for ne_set_request_body_fd() bug in <= 0.29.3. */\nstatic int send_length(void)\n{\n    ne_session *sess;\n    ne_request *req;\n    int fd;\n    ne_buffer *buf = ne_buffer_create();\n\n    fd = open(\"foobar.txt\", O_RDONLY);\n    ONV(fd < 0, (\"open random.txt failed: %s\", strerror(errno)));\n\n    CALL(make_session(&sess, serve_mirror, NULL));\n\n    req = ne_request_create(sess, \"GET\", \"/foo\");\n    \n    ne_set_request_body_fd(req, fd, 0, 3);\n    ne_add_response_body_reader(req, ne_accept_2xx, collector, buf);\n\n    ONREQ(ne_request_dispatch(req));\n\n    ONCMP(\"foo\", buf->data, \"response body\", \"match\");\n\n    ne_request_destroy(req);\n    ne_buffer_destroy(buf);\n    close(fd);\n    return destroy_and_wait(sess);\n}\n\n/* Test for error code for a SOCKS proxy failure, bug in <= 0.29.3. */\nstatic int socks_fail(void)\n{\n    ne_session *sess;\n    struct socks_server srv = {0};\n    int ret;\n\n    srv.version = NE_SOCK_SOCKSV5;\n    srv.failure = fail_init_vers;\n    srv.expect_port = 4242;\n    srv.expect_addr = ne_iaddr_parse(\"127.0.0.1\", ne_iaddr_ipv4);\n    srv.expect_fqdn = \"localhost\";\n    srv.username = \"bloggs\";\n    srv.password = \"guessme\";\n    \n    CALL(socksproxied_session_server(&sess, &srv, srv.expect_fqdn, srv.expect_port,\n                                     single_serve_string, EMPTY_RESP));\n\n    ret = any_request(sess, \"/blee\");\n    ONV(ret != NE_ERROR,\n        (\"request failed with %d not NE_ERROR\", ret));\n    ONV(strstr(ne_get_error(sess), \n               \"Could not establish connection from SOCKS proxy\") == NULL\n        || strstr(ne_get_error(sess),\n                  \"Invalid version in proxy response\") == NULL,\n        (\"unexpected error string: %s\", ne_get_error(sess)));\n\n    ne_iaddr_free(srv.expect_addr);\n\n    return destroy_and_wait(sess);\n}\n\nstatic int safe_flags(void)\n{\n    ne_session *sess = ne_session_create(\"http\", \"localhost\", 80);\n    ne_request *req = ne_request_create(sess, \"GET\", \"/\");\n\n    ne_set_request_flag(req, NE_REQFLAG_LAST, 0xAAAAAAAA);\n\n    ONN(\"flags array bound check failed\", ne_get_session(req) != sess);\n\n    ne_request_destroy(req);\n    ne_session_destroy(sess);\n\n    return OK;\n}\n\n/* Hit the timeout (2 seconds) for reading interim responses. */\nstatic int fail_excess_1xx(void)\n{\n    struct s1xx_args args = {20000000, 0};\n    return fail_request_with_error(0, serve_1xx, &args, 0,\n                                   \"Timed out reading interim responses\");\n}\n\nstatic int serve_check_reqline(ne_socket *sock, void *userdata)\n{\n    const char *expect = userdata;\n\n    ONN(\"failed to read request-line\",\n        ne_sock_readline(sock, buffer, BUFSIZ) <= 0);\n\n    NE_DEBUG(NE_DBG_HTTP, \"child: got request-line %s\\n\", buffer);\n\n    if (strcmp(expect, buffer) != 0)\n        return single_serve_string(sock, \"HTTP/1.1 400 Bad Request-Line\\r\\n\" EMPTY_RESP);\n    else\n        return single_serve_string(sock, RESP200 \"Connection: close\\r\\n\\r\\n\");\n}\n\n/* Test that various request target forms are allowed. */\nstatic int target_forms(void)\n{\n    static const struct {\n        const char *uri, *reqline;\n    } ts[] = {\n        { \"/foo\", \"GET /foo HTTP/1.1\\r\\n\" },\n        { \"/foo?bar\", \"GET /foo?bar HTTP/1.1\\r\\n\" },\n        { \"ftp://www.example.com/foo\", \"GET ftp://www.example.com/foo HTTP/1.1\\r\\n\" },\n        { \"*\", \"GET * HTTP/1.1\\r\\n\" },\n        { NULL, NULL }\n    };\n    unsigned n;\n\n    for (n = 0; ts[n].uri; n++) {\n        ne_session *sess;\n\n        CALL(make_session(&sess, serve_check_reqline, (void *)ts[n].reqline));\n\n        ONREQ(any_2xx_request(sess, ts[n].uri));\n\n        CALL(destroy_and_wait(sess));\n    }\n\n    return OK;\n}\n\n/* Interim response callback. */\nstatic void test_interim(void *userdata, ne_request *req, const ne_status *st)\n{\n    ne_buffer *buf = userdata;\n    const char *val;\n\n    ne_buffer_snprintf(buf, 15, \"[code=%d]\", st->code);\n\n    val = ne_get_response_header(req, \"X-Interim\");\n\n    ne_buffer_concat(buf, \"[hdr=\", val ? val : \"null\", \"]\", NULL);\n}\n\n/* Test for interim response headers. */\nstatic int interims(void)\n{\n    ne_session *sess;\n    ne_request *req;\n    ne_buffer *buf = ne_buffer_create();\n\n    CALL(make_session(&sess, single_serve_string,\n                      \"HTTP/1.1 103 Early Stuff\\r\\n\"\n                      \"X-Interim: foobar\\r\\n\" \"\\r\\n\"\n\n                      \"HTTP/1.1 102 Stuff Is Happening\\r\\n\"\n                      \"X-Interim: bar, foo\\r\\n\" \"\\r\\n\"\n\n                      \"HTTP/1.1 200 Thank you kindly\\r\\n\"\n                      \"Content-Length: 0\\r\\n\"\n                      \"X-Not-Interim: finally\\r\\n\" \"\\r\\n\"));\n\n    req = ne_request_create(sess, \"GET\", \"/\");\n    ne_add_interim_handler(req, test_interim, buf);\n    ONREQ(ne_request_dispatch(req));\n    ONN(\"interim header leaked to final response\",\n        ne_get_response_header(req, \"X-Interim\") != NULL);\n    ne_request_destroy(req);\n    CALL(destroy_and_wait(sess));\n\n    ONCMPN(\"[code=103][hdr=foobar][code=102][hdr=bar, foo]\", buf->data,\n           \"interim responses\", \"trace\");\n\n    ne_buffer_destroy(buf);\n    return OK;\n}\n\nstatic int retry_408(void)\n{\n    ne_session *sess;\n\n    /* Serve two responses down a single persistent connection, the\n     * second of which should be treated as a timed-out persistent\n     * connection, i.e. should be retried on a new connection. */\n    CALL(multi_session_server(&sess, \"http\",\n                              2, single_serve_string,\n                              EMPTY_RESP\n                              \"HTTP/1.1 408 Request Timeout\\r\\n\"\n                              \"Server: neon-test-server\\r\\n\"\n                              \"Content-Length: 0\\r\\n\\r\\n\"));\n\n    CALL(any_2xx_request(sess, \"/first408\"));\n    CALL(any_2xx_request(sess, \"/second408\"));\n\n    return destroy_and_wait(sess);\n}\n\n/* Ensure that only a 408 on a persisted connection is\n * retried. Otherwise it should just be handled as a final\n * response. */\nstatic int dont_retry_408(void)\n{\n    ne_session *sess;\n\n    CALL(make_session(&sess, single_serve_string,\n                      \"HTTP/1.1 408 Request Timeout\\r\\n\"\n                      \"Server: neon-test-server\\r\\n\"\n                      \"Content-Length: 0\\r\\n\\r\\n\"));\n\n    /* Run any request, ensure it gets a 408 response. */\n    CALL(run_request(sess, 408, construct_get, NULL));\n\n    return destroy_and_wait(sess);\n}\n\nstatic const char *ipv6_check_result = \"500 Something Went Wrong\";\n\n#define V6_EXAMPLE_HOST \"[2001:db8::cafe]\"\n\nstatic void ipv6_host_checker(char *value)\n{\n    NE_DEBUG(NE_DBG_HTTP, \"child: header value [%s]\\n\", value);\n    if (strcmp(value, V6_EXAMPLE_HOST) == 0)\n        ipv6_check_result = \"200 Good Header\";\n    else\n        ipv6_check_result = \"400 Bad Header\";\n}\n\n/* Server which acts as a proxy accepting a CONNECT request. */\nstatic int serve_v6_check(ne_socket *sock, void *ud)\n{\n    char resp[512];\n\n    got_header = ipv6_host_checker;\n    want_header = \"Host\";\n\n    CALL(discard_request(sock));\n\n    ne_snprintf(resp, sizeof resp, \"HTTP/1.1 %s\\r\\n\"\n                \"Content-Length: 0\\r\\n\"\n                \"Server: serve_v6_check\\r\\n\\r\\n\",\n                ipv6_check_result);\n\n    SEND_STRING(sock, resp);\n\n    return 0;\n}\n\nstatic int ipv6_literal(void)\n{\n    ne_session *sess;\n\n    CALL(fakeproxied_session_server(&sess, \"http\", V6_EXAMPLE_HOST,\n                                    80, serve_v6_check, NULL));\n\n    CALL(any_2xx_request(sess, \"/ipv6ish\"));\n\n    return destroy_and_wait(sess);\n}\n\nstatic int targets(void)\n{\n    struct {\n        const char *scheme;\n        const char *host;\n        int port;\n        const char *method;\n        const char *target;\n        const char *expected;\n    } ts[] = {\n        { \"http\", \"example.com\", 80, \"GET\", \"/fish\", \"http://example.com/fish\" },\n        { \"http\", \"example.com\", 8080, \"GET\", \"/fish\", \"http://example.com:8080/fish\" },\n        { \"https\", \"example.com\", 443, \"GET\", \"/\", \"https://example.com/\" },\n        { \"http\", \"proxy.example.com\", 80, \"GET\", \"ftp://example.com/fishfood\", \"ftp://example.com/fishfood\" },\n        { \"https\", \"example.com\", 443, \"OPTIONS\", \"*\", \"https://example.com\" },\n        { NULL }\n    };\n    unsigned n;\n\n    for (n = 0; ts[n].scheme != NULL; n++ ) {\n        const ne_uri *uri, *uri2;\n        ne_session *sess;\n        ne_request *req;\n        char *actual;\n\n        sess = ne_session_create(ts[n].scheme, ts[n].host, ts[n].port);\n        req = ne_request_create(sess, ts[n].method, ts[n].target);\n        uri = ne_get_request_target(req);\n        uri2 = ne_get_request_target(req);\n        actual = uri ? ne_uri_unparse(uri) : NULL;\n\n        ONCMP(ts[n].expected, actual, \"request target\", \"URI\");\n\n        ONN(\"caching failed, different rv on second call\", uri != uri2);\n\n        if (actual) ne_free(actual);\n\n        ne_request_destroy(req);\n        ne_session_destroy(sess);\n    }\n\n    return OK;\n}\n\n#define RETRY_DRIFT (2)\n\nstatic int retry_after(void)\n{\n    ne_session *sess;\n    static const struct {\n        const char *value;\n        time_t relative;\n        time_t absolute;\n    } *t, ts[] = {\n        { \"100\", 100, 0 },\n        { \"4242\", 4242, 0 },\n        { \"blah\", 0, 0 },\n        { \"Fri, 31 Dec 1999 23:59:59 GMT\", 0, 946684799 }\n    };\n    unsigned n;\n\n    for (n = 0; n < sizeof(ts)/sizeof(ts[0]); n++ ) {\n        char *resp = ne_concat(\"HTTP/1.1 429 Maybe Try Later\\r\\n\"\n                               \"Server: neon-test-server\\r\\n\"\n                               \"Retry-After: \", ts[n].value, \"\\r\\n\"\n                               \"Content-Length: 0\\r\\n\\r\\n\", NULL);\n        ne_request *req;\n        time_t expected, actual;\n\n        t = ts + n;\n\n        CALL(make_session(&sess, single_serve_string, resp));\n\n        req = ne_request_create(sess, \"GET\", \"/\");\n        ONREQ(ne_request_dispatch(req));\n        actual = ne_get_response_retry_after(req);\n        ne_request_destroy(req);\n\n        if (t->absolute == 0 && t->relative == 0) {\n            ONV(actual != 0,\n                (\"expected error return for %s, got %\" NE_FMT_TIME_T,\n                 t->value, actual));\n        }\n        else {\n            expected  = t->relative ? time(NULL) + t->relative\n                : t->absolute;\n\n            ONV(actual < expected - RETRY_DRIFT\n                || actual > expected + RETRY_DRIFT,\n                (\"retry-after actual %\" NE_FMT_TIME_T\n                 \" doesn't match expected %\" NE_FMT_TIME_T\n                 \" for %s\", actual, expected, t->value));\n        }\n\n        \n        CALL(destroy_and_wait(sess));\n        ne_free(resp);\n    }\n\n    return OK;\n}\n\n/* TODO: test that ne_set_notifier(, NULL, NULL) DTRT too. */\n\nne_test tests[] = {\n    T(lookup_localhost),\n    T(response_bodies),\n    T(no_body_204),\n    T(no_body_304),\n    T(no_body_HEAD),\n    T(reason_phrase),\n    T(chunk_oversize),\n    T(no_body_chunks),\n    T(persist_http11),\n    T(persist_chunked),\n    T(persist_http10),\n    T(persist_proxy_http10),\n    T(persist_timeout),\n    T(no_persist_http10),\n    T(ptimeout_eof),\n    T(ptimeout_eof2),\n    T(closed_connection),\n    T(close_not_retried),\n    T(send_progress),\n    T(response_headers),\n    T(response_header_nul),\n    T(reset_headers),\n    T(iterate_none),\n    T(iterate_many),\n    T(skip_interim_1xx),\n    T(skip_many_1xx),\n    T(skip_1xx_hdrs),\n    T(send_bodies),\n    T(expect_100_once),\n    T(expect_100_nobody),\n    T(unbounded_headers),\n    T(unbounded_folding),\n    T(blank_response),\n    T(not_http),\n    T(fail_eof_continued),\n    T(fail_eof_headers),\n    T(fail_eof_chunk),\n    T(fail_eof_badclen),\n    T(fail_long_header),\n    T(fail_on_invalid),\n    T(read_timeout),\n    T(fail_connect),\n    T(proxy_no_resolve),\n    T(fail_chunksize),\n    T(abort_respbody),\n    T(retry_after_abort),\n    T(fail_statusline),\n    T(dup_method),\n    T(versions),\n    T(hook_create_req),\n    T(abort_reader),\n    T(send_bad_offset),\n    T(hooks),\n    T(hook_self_destroy),\n    T(icy_protocol),\n    T(status),\n    T(status_chunked),\n    T(local_addr),\n    T(dereg_progress),\n    T(addrlist),\n    T(socks_proxy),\n    T(socks_v4_proxy),\n    T(send_length),\n    T(socks_fail),\n    T(fail_lookup),\n    T(fail_double_lookup),\n    T(safe_flags),\n    T(fail_excess_1xx),\n    T(target_forms),\n    T(interims),\n    T(retry_408),\n    T(dont_retry_408),\n    T(ipv6_literal),\n#if 0\n    T(redirect_error),\n#endif\n    T(targets),\n    T(retry_after),\n    T(NULL)\n};\n"
  },
  {
    "path": "test/resolve.c",
    "content": "/* \n   Test program for the neon resolver interface\n   Copyright (C) 2002-2003, Joe Orton <joe@manyfish.co.uk>\n\n   This program is free software; you can redistribute it and/or modify\n   it under the terms of the GNU General Public License as published by\n   the Free Software Foundation; either version 2 of the License, or\n   (at your option) any later version.\n  \n   This program is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU General Public License for more details.\n  \n   You should have received a copy of the GNU General Public License\n   along with this program; if not, write to the Free Software\n   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\n*/\n\n#include \"config.h\"\n\n#include <stdio.h>\n\n#include \"ne_socket.h\"\n\nint main(int argc, char **argv)\n{\n    ne_sock_addr *addr;\n    char buf[256];\n    int ret = 0;\n\n    if (argc < 2) {\n\tprintf(\"Usage: %s hostname\\n\", argv[0]);\n\treturn 1;\n    }\n    \n    if (ne_sock_init()) {\n\tprintf(\"%s: Failed to initialize socket library.\\n\", argv[0]);\n        return 1;\n    }\n\n    addr = ne_addr_resolve(argv[1], 0);\n    if (ne_addr_result(addr)) {\n\tprintf(\"Could not resolve `%s': %s\\n\", argv[1],\n\t       ne_addr_error(addr, buf, sizeof buf));\n\tret = 2;\n    } else {\n\tconst ne_inet_addr *ia;\n\tprintf(\"Resolved `%s' OK:\", argv[1]);\n\tfor (ia = ne_addr_first(addr); ia; ia = ne_addr_next(addr)) {\n\t    printf(\" <%s>\", ne_iaddr_print(ia, buf, sizeof buf));\n\t}\n\tputchar('\\n');\n    }\n    ne_addr_destroy(addr);\n\n    return ret;\n}\n"
  },
  {
    "path": "test/run-tests.sh",
    "content": "#!/bin/sh\n#\n# This script can be used to run the installed neon test suite\n# against an installed copy of the neon library.\n# \n\n# enable glibc malloc safety checks\nMALLOC_CHECK_=2\nMALLOC_PERTURB_=242\nexport MALLOC_CHECK_ MALLOC_PERTURB_\n\ncd data\n\nif test -x ../bin/ssl; then\n    rm -rf ca\n\n    touch ../configure\n\n    echo \"INIT: generating SSL ceritifcates...\"\n    if sh ./makekeys 2> makekeys.out; then :; else\n        echo FAIL: could not generate SSL certificates\n        exit 2\n    fi\nfi\n\nfor t in ../bin/*; do\n    if ${t}; then :; else\n        echo FAIL: ${t}\n        exit 1\n    fi\ndone\n\necho \"PASS: all tests passed\"\n\nexit 0\n"
  },
  {
    "path": "test/run.sh",
    "content": "#!/bin/sh\n\nrm -f debug.log child.log\n\nulimit -c unlimited\nulimit -t 120\n\nunset LANG\nunset LC_MESSAGES\n\n# Enable glibc heap consistency checks, and memory randomization.\nMALLOC_CHECK_=2\nMALLOC_PERTURB_=`expr $RANDOM % 255 2>/dev/null`\nexport MALLOC_CHECK_ MALLOC_PERTURB_\n\nexport GNUTLS_SYSTEM_PRIORITY_FILE=$PWD/neon.prio\n\nexport TEST_QUIET=${TEST_QUIET:-1}\nKEEP_GOING=${KEEP_GOING:-0}\n\nRETVAL=0\n\nfor f in $*; do\n    if ${HARNESS} ./$f ${SRCDIR}; then\n        :\n    else\n        RETVAL=$?\n        echo ' -->>>' \"$f failed => ${RETVAL}\"\n        [ $KEEP_GOING -eq 1 ] || break\n    fi\ndone\n\nexit $RETVAL\n"
  },
  {
    "path": "test/session.c",
    "content": "/* \n   Tests for session handling\n   Copyright (C) 2002-2006, 2009, Joe Orton <joe@manyfish.co.uk>\n\n   This program is free software; you can redistribute it and/or modify\n   it under the terms of the GNU General Public License as published by\n   the Free Software Foundation; either version 2 of the License, or\n   (at your option) any later version.\n  \n   This program is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU General Public License for more details.\n  \n   You should have received a copy of the GNU General Public License\n   along with this program; if not, write to the Free Software\n   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\n*/\n\n#include \"config.h\"\n\n#include <sys/types.h>\n\n#ifdef HAVE_STDLIB_H\n#include <stdlib.h>\n#endif\n#ifdef HAVE_UNISTD_H\n#include <unistd.h>\n#endif\n\n#include \"ne_session.h\"\n#include \"ne_alloc.h\"\n\n#include \"tests.h\"\n\nstatic int fill_uri(void)\n{\n    static const struct {\n        const char *scheme;\n        const char *host;\n        unsigned int port;\n        const char *uri;\n    } ts[] = {\n        { \"http\", \"localhost\", 1234, \"http://localhost:1234\" },\n        { \"HTTPS\", \"localhost\", 999, \"https://localhost:999\" },\n        { \"ftp\", \"[::1]\", 42, \"ftp://[::1]:42\" },\n        { NULL, NULL, 0 }\n    };\n    unsigned int i;\n\n    for (i = 0; ts[i].scheme != NULL; i++) {\n        ne_session *sess = ne_session_create(ts[i].scheme, ts[i].host, ts[i].port);\n        ne_uri uri = {0};\n        char *unp;\n\n        ne_fill_server_uri(sess, &uri);\n        uri.path = ne_strdup(\"\");\n\n        unp = ne_uri_unparse(&uri);\n        ONCMPN(ts[i].uri, unp, \"expanded URI\", \"session\");\n\n        ne_free(unp);\n        ne_session_destroy(sess);\n        ne_uri_free(&uri);\n    }\n\n    return OK;\n}\n\nstatic int fill_proxy_uri(void)\n{\n    ne_uri uri = {0};\n    ne_session *sess = ne_session_create(\"http\", \"localhost\", 1234);\n\n    ne_fill_proxy_uri(sess, &uri);\n    \n    ONN(\"no proxy host should be set\", uri.host != NULL);\n    ONN(\"no proxy port should be set\", uri.port != 0);\n    \n    ne_session_proxy(sess, \"www.example.com\", 345);\n\n    ne_fill_proxy_uri(sess, &uri);\n\n    ONCMP(\"www.example.com\", uri.host, \"fill_proxy_uri\", \"host\");\n    ONN(\"proxy port mis-match\", uri.port != 345);\n\n    ne_session_destroy(sess);\n    ne_uri_free(&uri);\n\n    return OK;\n}\n\n\nstatic int match_hostport(const char *scheme, const char *hostname, int port,\n\t\t\t  const char *hostport)\n{\n    ne_session *sess = ne_session_create(scheme, hostname, port);\n    const char *hp = ne_get_server_hostport(sess);\n    ONV(strcmp(hp, hostport),\n\t(\"hostport incorrect for %s: `%s' not `%s'\", scheme, hp, hostport));\n    ne_session_destroy(sess);\n    return OK;\n}\n\nstatic int hostports(void)\n{\n    static const struct {\n\tconst char *scheme, *hostname;\n\tint port;\n\tconst char *hostport;\n    } hps[] = {\n\t{ \"http\", \"host.name\", 80, \"host.name\" },\n\t{ \"http\", \"host.name\", 555, \"host.name:555\" },\n\t{ \"http\", \"host.name\", 443, \"host.name:443\" },\n\t{ \"https\", \"host.name\", 80, \"host.name:80\" },\n\t{ \"https\", \"host.name\", 443, \"host.name\" },\n\t{ \"https\", \"host.name\", 700, \"host.name:700\" },\n\t{ NULL }\n    };\n    int n;\n\n    for (n = 0; hps[n].scheme; n++) {\n\tCALL(match_hostport(hps[n].scheme, hps[n].hostname,\n\t\t\t    hps[n].port, hps[n].hostport));\n    }\n\n    return OK;\n}\n\n\n/* Check that ne_set_error is passing through to printf correctly. */\nstatic int errors(void)\n{\n    ne_session *sess = ne_session_create(\"http\", \"foo.com\", 80);\n    \n#define EXPECT \"foo, hello world, 100, bar!\"\n\n    ne_set_error(sess, \"foo, %s, %d, bar!\", \"hello world\", 100);\n\n    ONV(strcmp(ne_get_error(sess), EXPECT),\n\t(\"session error was `%s' not `%s'\",\n\t ne_get_error(sess), EXPECT));\n#undef EXPECT\n\n    ne_session_destroy(sess);\n    return OK;    \n}\n\n#define ID1 \"foo\"\n#define ID2 \"bar\"\n\nstatic int privates(void)\n{\n    ne_session *sess = ne_session_create(\"http\", \"localhost\", 80);\n    char *v1 = \"hello\", *v2 = \"world\";\n\n    ne_set_session_private(sess, ID1, v1);\n    ne_set_session_private(sess, ID2, v2);\n\n#define PRIV(msg, id, val) \\\nONN(msg, ne_get_session_private(sess, id) != val)\n\n    PRIV(\"private #1 wrong\", ID1, v1);\n    PRIV(\"private #2 wrong\", ID2, v2);\n    PRIV(\"unknown id wrong\", \"no such ID\", NULL);\n\n    ne_session_destroy(sess);\n    return OK;    \n}\n\n/* test that ne_session_create doesn't really care what scheme you\n * give it, and that ne_get_scheme() works. */\nstatic int get_scheme(void)\n{\n    static const char *schemes[] = {\n        \"http\", \"https\", \"ftp\", \"ldap\", \"foobar\", NULL\n    };\n    int n;\n\n    for (n = 0; schemes[n]; n++) {\n        ne_session *sess = ne_session_create(schemes[n], \"localhost\", 80);\n        ONV(strcmp(ne_get_scheme(sess), schemes[n]),\n            (\"scheme was `%s' not `%s'!\", ne_get_scheme(sess), schemes[n]));\n        ne_session_destroy(sess);\n    }\n    \n    return OK;\n}\n\nstatic int flags(void)\n{\n    ne_session *sess = ne_session_create(\"https\", \"localhost\", 443);\n\n    ne_set_session_flag(sess, NE_SESSFLAG_PERSIST, 1);\n    ONN(\"persist flag was not set\",\n        ne_get_session_flag(sess, NE_SESSFLAG_PERSIST) != 1);\n\n    ne_set_session_flag(sess, NE_SESSFLAG_LAST, 1);\n    ONN(\"unsupported flag was recognized\",\n        ne_get_session_flag(sess, NE_SESSFLAG_LAST) != -1);\n\n    ne_session_destroy(sess);\n\n    return OK;\n}\n\nstatic int proxies(void)\n{\n    ne_session *sess = ne_session_create(\"https\", \"localhost\", 443);\n\n    ne_session_proxy(sess, \"http\", 80);\n    ne_set_addrlist2(sess, 80, NULL, 0);\n\n    ne_session_destroy(sess);\n\n    return OK;\n}\n\nstatic int tls_names(void)\n{\n    static const struct {\n        unsigned int proto;\n        const char *expected;\n    } ts[] = {\n        { NE_SSL_PROTO_SSL_3, \"SSLv3\" },\n        { NE_SSL_PROTO_TLS_1_0, \"TLSv1.0\" },\n        { NE_SSL_PROTO_TLS_1_1, \"TLSv1.1\" },\n        { NE_SSL_PROTO_TLS_1_2, \"TLSv1.2\" },\n        { NE_SSL_PROTO_TLS_1_3, \"TLSv1.3\" },\n        { 0 },\n    };\n    unsigned n;\n\n    for (n = 0; ts[n].proto; n++) {\n        const char *actual = ne_ssl_proto_name(ts[n].proto);\n\n        ONCMP(ts[n].expected, actual, \"TLS\", \"protocol name\");\n    }\n\n    return OK;\n}\n\nne_test tests[] = {\n    T(fill_uri),\n    T(fill_proxy_uri),\n    T(hostports),\n    T(errors),\n    T(privates),\n    T(get_scheme),\n    T(flags),\n    T(proxies),\n    T(tls_names),\n    T(NULL)\n};\n\n"
  },
  {
    "path": "test/skeleton.c",
    "content": "/* \n   neon test suite\n   Copyright (C) 2002-2003, Joe Orton <joe@manyfish.co.uk>\n\n   This program is free software; you can redistribute it and/or modify\n   it under the terms of the GNU General Public License as published by\n   the Free Software Foundation; either version 2 of the License, or\n   (at your option) any later version.\n  \n   This program is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU General Public License for more details.\n  \n   You should have received a copy of the GNU General Public License\n   along with this program; if not, write to the Free Software\n   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\n*/\n\n#include \"config.h\"\n\n#include <sys/types.h>\n\n#ifdef HAVE_STDLIB_H\n#include <stdlib.h>\n#endif\n#ifdef HAVE_UNISTD_H\n#include <unistd.h>\n#endif\n\n#include \"ne_request.h\"\n#include \"ne_socket.h\"\n\n#include \"tests.h\"\n#include \"child.h\"\n#include \"utils.h\"\n\nstatic int foo(void)\n{\n    /* This is a skeleton test suite file. */\n    return OK;\n}\n\nne_test tests[] = {\n    T(foo), /* test functions here */\n\n    /* end of test functions. */\n    T(NULL) \n};\n\n"
  },
  {
    "path": "test/socket.c",
    "content": "/* \n   Socket handling tests\n   Copyright (C) 2002-2011, Joe Orton <joe@manyfish.co.uk>\n\n   This program is free software; you can redistribute it and/or modify\n   it under the terms of the GNU General Public License as published by\n   the Free Software Foundation; either version 2 of the License, or\n   (at your option) any later version.\n  \n   This program is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU General Public License for more details.\n  \n   You should have received a copy of the GNU General Public License\n   along with this program; if not, write to the Free Software\n   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\n*/\n\n/* This module can be compiled with -DSOCKET_SSL enabled, to run all\n * the tests over an SSL connection. */\n\n#include \"config.h\"\n\n#include <sys/types.h>\n#include <sys/socket.h> /* for AF_INET6 */\n\n#ifdef HAVE_STDLIB_H\n#include <stdlib.h>\n#endif\n#ifdef HAVE_STRING_H\n#include <string.h>\n#endif\n#ifdef HAVE_UNISTD_H\n#include <unistd.h> /* for gethostname() */\n#endif\n#include <time.h> /* for time() */\n\n#include \"ne_socket.h\"\n#include \"ne_utils.h\"\n#include \"ne_alloc.h\"\n\n#include \"child.h\"\n#include \"tests.h\"\n#include \"utils.h\"\n\n#ifdef SOCKET_SSL\n#include \"ne_ssl.h\"\nne_ssl_context *server_ctx, *client_ctx_tls12, *client_ctx;\n#endif\n\nstatic ne_inet_addr *localhost;\nstatic char buffer[BUFSIZ];\n\n#if defined(AF_INET6) && defined(USE_GETADDRINFO)\n#define TEST_IPV6\n#endif\n\n/* tests for doing init/finish multiple times. */\nstatic int multi_init(void)\n{\n    int res1 = ne_sock_init(), res2 = ne_sock_init();\n    \n    ONV(res1 != res2, (\"cached init result changed from %d to %d\",\n                       res1, res2));\n    \n    ne_sock_exit();\n    ne_sock_exit();\n    ne_sock_exit();\n\n    res1 = ne_sock_init();\n    ONV(res1 != res2, (\"re-init after exit gave %d not %d\",\n                       res1, res2));\n    ne_sock_exit();\n\n    res2 = ne_sock_init();\n    \n    ONV(res1 != res2, (\"second time, cached init result changed from %d to %d\",\n                       res1, res2));\n    \n    return OK;\n}\n\n/* Create and connect *sock to address addr on given port. */\nstatic int do_connect(ne_socket **sock, const ne_inet_addr *addr, unsigned int port)\n{\n    char ianame[256];\n\n    *sock = ne_sock_create();\n    ONN(\"could not create socket\", *sock == NULL);\n    \n    ONV(ne_sock_connect(*sock, addr, port) != 0,\n        (\"could not connect to server '%s': %s\",\n         ne_iaddr_print(addr, ianame, sizeof ianame),\n         ne_sock_error(*sock)));\n\n    return OK;\n}\n\nstatic int close_and_wait(ne_socket *sock)\n{\n    int ret = ne_sock_close(sock);\n\n    ONV(ret, (\"failed closing socket: %d\", ret));\n\n    return await_server();\n}\n\n#ifdef SOCKET_SSL\n\nstatic int init_ssl(void)\n{\n    ne_ssl_certificate *cert;\n\n    ONN(\"sock_init failed\", ne_sock_init());\n    server_ctx = ne_ssl_context_create(1);\n    ONN(\"SSL_CTX_new failed\", server_ctx == NULL);\n\n    ne_ssl_context_keypair(server_ctx, \"server.cert\", \"server.key\");\n\n    client_ctx = ne_ssl_context_create(NE_SSL_CTX_CLIENT);\n    ONN(\"SSL_CTX_new failed for client\", client_ctx == NULL);\n\n    client_ctx_tls12 = ne_ssl_context_create(NE_SSL_CTX_CLIENT);\n    ONN(\"SSL_CTX_new failed for client\", client_ctx_tls12 == NULL);\n    ne_ssl_context_set_versions(client_ctx_tls12, NE_SSL_PROTO_TLS_1_2,\n                                NE_SSL_PROTO_TLS_1_2);\n    \n    cert = ne_ssl_cert_read(\"ca/cert.pem\");\n    ONN(\"could not load ca/cert.pem\", cert == NULL);\n\n    ne_ssl_context_trustcert(client_ctx, cert);\n    ne_ssl_context_trustcert(client_ctx_tls12, cert);\n\n    return OK;\n}\n#endif\n\nstatic int resolve(void)\n{\n    CALL(lookup_localhost());\n    localhost = get_lh_inet_addr();\n    return OK;\n}\n\nstatic int serve_close(ne_socket *sock, void *ud)\n{\n    return 0;\n}\n\n#ifdef SOCKET_SSL\nstruct serve_pair {\n    server_fn fn;\n    void *userdata;\n};\n\nstatic int wrap_serve(ne_socket *sock, void *ud)\n{\n    struct serve_pair *pair = ud;\n    \n    if (ne_sock_accept_ssl(sock, server_ctx)) {\n\tNE_DEBUG(NE_DBG_SOCKET, \"SSL_accept failed: %s\\n\", ne_sock_error(sock));\n\treturn 1;\n    }\n    \n    NE_DEBUG(NE_DBG_SOCKET, \"SSL accept okay.\\n\");\n    return pair->fn(sock, pair->userdata);\n}\n\nstatic int beginc(ne_socket **sock, ne_ssl_context *ctx, server_fn fn, void *ud)\n{\n    struct serve_pair pair;\n    unsigned int port;\n    pair.fn = fn;\n    pair.userdata = ud;\n    CALL(new_spawn_server(1, wrap_serve, &pair, &port));\n    CALL(do_connect(sock, localhost, port));\n    ONV(ne_sock_connect_ssl(*sock, ctx, NULL),\n\t(\"SSL negotiation failed: %s\", ne_sock_error(*sock)));\n    return OK;\n}\n\nstatic int begin(ne_socket **sock, server_fn fn, void *ud)\n{\n    return beginc(sock, client_ctx, fn, ud);\n}\n\n#else\n/* non-SSL begin() function. */\nstatic int begin(ne_socket **sock, server_fn fn, void *ud)\n{\n    unsigned int port;\n    CALL(new_spawn_server(1, fn, ud, &port));\n    return do_connect(sock, localhost, port);\n}\n#endif\n\nstatic int resolve_numeric(void)\n{\n    ne_sock_addr *addr = ne_addr_resolve(\"127.0.0.1\", 0);\n    ONV(ne_addr_result(addr),\n\t(\"failed to resolve 127.0.0.1: %s\",\n\t ne_addr_error(addr, buffer, sizeof buffer)));\n    ONN(\"ne_addr_first returned NULL\", ne_addr_first(addr) == NULL);\n    ONN(\"ne_iaddr_print didn't return buffer\", \n\tne_iaddr_print(ne_addr_first(addr), buffer, sizeof buffer) != buffer);\n    ONV(strcmp(buffer, \"127.0.0.1\"), (\"ntop gave `%s' not 127.0.0.1\", buffer));\n    ne_addr_destroy(addr);\n    return OK;\n}\n\n#if 0\nstatic int resolve_ipv6(void)\n{\n    char err[256];\n    ne_sock_addr *addr = ne_addr_resolve(\"[::1]\", 0);\n    ONV(ne_addr_result(addr),\n\t(\"could not resolve `[::1]': %s\",\n\t ne_addr_error(addr, err, sizeof err)));\n    ne_addr_destroy(addr);\n    return OK;\n}\n#endif\n\nstatic const unsigned char raw_127[4] = \"\\x7f\\0\\0\\01\", /* 127.0.0.1 */\n    raw6_nuls[16] = /* :: */ \"\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\";\nstatic const unsigned char\nraw6_cafe[16] = /* feed::cafe */ \"\\xfe\\xed\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\xca\\xfe\";\n#ifdef TEST_IPV6\nstatic const unsigned char \nraw6_babe[16] = /* cafe:babe:: */ \"\\xca\\xfe\\xba\\xbe\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\";\n#endif\n\n/* Check the given inet addr is 127.0.0.1. */\nstatic int check_is_raw127(const ne_inet_addr *ia)\n{\n    unsigned char raw[5];\n\n    raw[4] = 'Z';\n    ONN(\"bogus ne_iaddr_typeof return\", ne_iaddr_typeof(ia) != ne_iaddr_ipv4);\n    ONN(\"ne_iaddr_raw gave bad retval\", ne_iaddr_raw(ia, raw) != raw);\n    ONN(\"raw address mismatch\", memcmp(raw, raw_127, 4) != 0);\n    ONN(\"ne_iaddr_raw buffer overflow\", raw[4] != 'Z');\n\n    return OK;\n}\n\nstatic int addr_make_v4(void)\n{\n    ne_inet_addr *ia;\n    char pr[50];\n    \n    ia = ne_iaddr_make(ne_iaddr_ipv4, raw_127);\n    ONN(\"ne_iaddr_make returned NULL\", ia == NULL);\n\n    ne_iaddr_print(ia, pr, sizeof pr);\n    ONV(strcmp(pr, \"127.0.0.1\"), (\"address was %s not 127.0.0.1\", pr));\n\n    CALL(check_is_raw127(ia));\n    \n    ne_iaddr_free(ia);\n\n    return OK;\n}\n\nstatic int parse_v4(void)\n{\n    ne_inet_addr *ia;\n\n    ia = ne_iaddr_parse(\"127.0.0.1\", ne_iaddr_ipv4);\n    ONN(\"parse failed\", ia == NULL);\n\n    CALL(check_is_raw127(ia));\n\n    ne_iaddr_free(ia);\n\n    return OK;\n}\n\nstatic int addr_make_v6(void)\n{\n#ifdef TEST_IPV6   \n    struct {\n\tconst unsigned char *addr;\n\tconst char *rep;\n    } as[] = {\n\t{ raw6_cafe, \"feed::cafe\" },\n\t{ raw6_babe, \"cafe:babe::\" },\n\t{ raw6_nuls, \"::\" },\n\t{ NULL, NULL }\n    };\n    int n;\n    \n    for (n = 0; as[n].rep != NULL; n++) {\n\tne_inet_addr *ia = ne_iaddr_make(ne_iaddr_ipv6, as[n].addr);\n\tchar pr[128];\n        unsigned char raw[17];\n\n\tONV(ia == NULL, (\"could not make address for '%s'\", \n                         as[n].rep));\n\n\tne_iaddr_print(ia, pr, sizeof pr);\n\tONV(strcmp(pr, as[n].rep), \n\t    (\"address %d was '%s' not '%s'\", n, pr, as[n].rep));\n\t\n        ONN(\"bogus ne_iaddr_typeof return\", ne_iaddr_typeof(ia) != ne_iaddr_ipv6);\n\n        raw[16] = 'Z';\n        ONN(\"ne_iaddr_raw gave bad retval\", ne_iaddr_raw(ia, raw) != raw);\n        ONN(\"raw address mismatch\", memcmp(raw, as[n].addr, 4) != 0);\n        ONN(\"ne_iaddr_raw buffer overflow\", raw[16] != 'Z');\n        \n\tne_iaddr_free(ia);\n        \n        ia = ne_iaddr_parse(as[n].rep, ne_iaddr_ipv6);\n        ONV(ia == NULL, (\"ne_iaddr_parse failed for %s\", as[n].rep));\n        ONN(\"bogus ne_iaddr_typeof return\", ne_iaddr_typeof(ia) != ne_iaddr_ipv6);\n        ONN(\"ne_iaddr_raw gave bad retval\", ne_iaddr_raw(ia, raw) != raw);\n        ONN(\"raw address mismatch\", memcmp(raw, as[n].addr, 4) != 0);\n        ONN(\"ne_iaddr_raw buffer overflow\", raw[16] != 'Z');\n\n        ne_iaddr_free(ia);\n   }\n\n    return OK;\n#else\n    /* should fail when lacking IPv6 support. */\n    ne_inet_addr *ia = ne_iaddr_make(ne_iaddr_ipv6, raw6_nuls);\n    ONN(\"ne_iaddr_make did not return NULL\", ia != NULL);\n    ONN(\"ne_iaddr_parse did not return NULL\", ne_iaddr_parse(\"127.0.0.1\", ne_iaddr_ipv6));\n#endif\n    return OK;\n}\n\nstatic const unsigned char raw_1234[] = \"\\x01\\x02\\x03\\x04\";\n\nstatic int addr_compare(void)\n{\n    ne_inet_addr *ia1, *ia2;\n    int ret;\n\n    ia1 = ne_iaddr_make(ne_iaddr_ipv4, raw_127);\n    ia2 = ne_iaddr_make(ne_iaddr_ipv4, raw_127);\n    ONN(\"addr_make returned NULL\", !ia1 || !ia2);\n\n    ret = ne_iaddr_cmp(ia1, ia2);\n    ONV(ret != 0, (\"comparison of equal IPv4 addresses was %d\", ret));\n    ne_iaddr_free(ia2);\n\n    ia2 = ne_iaddr_make(ne_iaddr_ipv4, raw_1234);\n    ret = ne_iaddr_cmp(ia1, ia2);\n    ONN(\"comparison of unequal IPv4 addresses was zero\", ret == 0);\n    \n#ifdef TEST_IPV6\n    ne_iaddr_free(ia2);\n    ia2 = ne_iaddr_make(ne_iaddr_ipv6, raw6_cafe);\n    ONN(\"could not make IPv6 address\", !ia2);\n    ret = ne_iaddr_cmp(ia1, ia2);\n    ONN(\"comparison of IPv4 and IPv6 addresses was zero\", ret == 0);\n\n    ne_iaddr_free(ia1);\n    ia1 = ne_iaddr_make(ne_iaddr_ipv6, raw6_cafe);\n    ret = ne_iaddr_cmp(ia1, ia2);\n    ONN(\"comparison of equal IPv6 addresses was not zero\", ret != 0);\n\n    ne_iaddr_free(ia1);\n    ia1 = ne_iaddr_make(ne_iaddr_ipv6, raw6_babe);\n    ret = ne_iaddr_cmp(ia1, ia2);\n    ONN(\"comparison of unequal IPv6 address was zero\", ret == 0);\n#endif    \n\n    ne_iaddr_free(ia1);\n    ne_iaddr_free(ia2);\n    return OK;\n}\n\nstatic int addr_put(void)\n{\n    ne_inet_addr *ia, *ia2;\n\n    ia = ne_iaddr_parse(\"127.0.0.1\", ne_iaddr_ipv4);\n    ONN(\"parse failed\", ia == NULL);\n    CALL(check_is_raw127(ia));\n\n    ia2 = ne_iaddr_put(ia, ne_iaddr_ipv4, raw_1234);\n    ONN(\"new pointer returned after _put\", ia2 != ia);\n    ONN(\"bogus ne_iaddr_typeof return\", ne_iaddr_typeof(ia) != ne_iaddr_ipv4);\n\n#ifdef TEST_IPV6\n    ia2 = ne_iaddr_put(ia, ne_iaddr_ipv6, raw6_cafe);\n    ONN(\"new pointer returned after _put\", ia2 != ia);\n    ONN(\"bogus ne_iaddr_typeof return\", ne_iaddr_typeof(ia) != ne_iaddr_ipv6);\n#else\n    ia2 = ne_iaddr_put(ia, ne_iaddr_ipv6, raw6_cafe);\n    ONN(\"new pointer must return NULL for IPv6\", ia2 != NULL);\n#endif\n\n    ne_iaddr_free(ia);\n    return OK;\n}\n\nstatic int addr_reverse(void)\n{\n    ne_inet_addr *ia = ne_iaddr_make(ne_iaddr_ipv4, raw_127);\n    char buf[128], *syshost = NULL;\n    int match;\n\n#ifdef HAVE_GETHOSTNAME\n    char host[128];\n\n    if (gethostname(host, sizeof host) == 0) {\n        syshost = host;\n    }\n#endif\n\n    ONN(\"ne_iaddr_make returned NULL\", ia == NULL);\n\n    ONN(\"reverse lookup for 127.0.0.1 failed\",\n        ne_iaddr_reverse(ia, buf, sizeof buf) != 0);\n\n    NE_DEBUG(NE_DBG_SOCKET, \"Reverse lookup for 127.0.0.1 => %s\\n\", buf);\n\n    match = strcmp(buf, \"localhost.localdomain\") == 0\n        || strcmp(buf, \"localhost\") == 0;\n\n    if (!match && syshost)\n        /* If the returned name has the system hostname as a prefix, that's\n         * good enough. */\n        match = strncmp(buf, syshost, strlen(syshost)) == 0;\n\n    if (!match)\n        t_warning(\"reverse lookup for 127.0.0.1 got '%s'\", buf);\n    \n    ONN(\"reverse lookup for 127.0.0.1 got empty string\", strlen(buf) == 0);\n\n    ne_iaddr_free(ia);\n\n    return OK;\n}\n\nstatic int addr_canonical(void)\n{\n    ne_sock_addr *sa;\n    const char *h;\n\n    sa = ne_addr_resolve(\"localhost\", NE_ADDR_CANON);\n    ONN(\"could not resolve localhost\", sa == NULL);\n    \n    h = ne_addr_canonical(sa);\n    ONN(\"no canonical name for localhost\", h == NULL);\n\n    NE_DEBUG(NE_DBG_SOCKET, \"canonical name: %s\\n\", h);\n\n    ne_addr_destroy(sa);\n    \n    return OK;\n}\n\nstatic int addr_failures(void)\n{\n    static const char *hosts[] = {\n        \"nonesuch.example.com\",\n        \"absolutelynodomain1231241255.com\",\n        NULL\n    };\n    unsigned n;\n\n    if (getenv(\"TEST_RESOLVER\") == NULL) {\n        t_context(\"not testing resolver failure cases\");\n        return SKIP;\n    }\n\n    for (n = 0; hosts[n]; n++) {\n        ne_sock_addr *sa = ne_addr_resolve(hosts[n], 0);\n        char buf[BUFSIZ], *err;\n\n        ONN(\"resolver failed\", sa == NULL);\n        ONN(\"should get lookup failure for bad domain\", ne_addr_result(sa) == 0);\n        err = ne_addr_error(sa, buf, sizeof buf);\n        ONN(\"no error pointer\", err == NULL);\n        ONN(\"bad error pointer\", err != buf);\n        ONN(\"empty error\", strcmp(err, \"\") == 0);\n\n        ne_addr_destroy(sa);\n    }\n\n    return OK;\n}\n\n\nstatic int just_connect(void)\n{\n    ne_socket *sock;\n    \n    CALL(begin(&sock, serve_close, NULL));\n\n    return close_and_wait(sock);\n}\n\n/* Connect to an address crafted using ne_iaddr_make rather than from\n * the resolver. */\nstatic int addr_connect(void)\n{\n    ne_socket *sock = ne_sock_create();\n    ne_inet_addr *ia;\n    unsigned int port;\n\n    ia = get_lh_inet_addr();\n    ONN(\"ne_iaddr_make returned NULL\", ia == NULL);\n    \n    CALL(new_spawn_server(1, serve_close, NULL, &port));\n    ONN(\"could not connect\", ne_sock_connect(sock, ia, port));\n    ne_iaddr_free(ia);\n\n    return close_and_wait(sock);\n}\n\nstatic int addr_peer(void)\n{\n    ne_socket *sock = ne_sock_create();\n    ne_inet_addr *ia, *ia2;\n    unsigned int port = 9999, realport;\n    int ret;\n\n    ia = get_lh_inet_addr();\n    ONN(\"ne_iaddr_make returned NULL\", ia == NULL);\n    \n    CALL(new_spawn_server(1, serve_close, NULL, &realport));\n    ONN(\"could not connect\", ne_sock_connect(sock, ia, realport));\n\n    ia2 = ne_sock_peer(sock, &port);\n    ret = ne_iaddr_cmp(ia, ia2);\n    ONV(ret != 0,\n        (\"comparison of peer with server address was %d\", ret));\n\n    ONV(port != realport, (\"got peer port %u, expected %u\", port, realport));\n \n    ne_sock_close(sock);\n    CALL(await_server());\n\n    ne_iaddr_free(ia);\n    ne_iaddr_free(ia2);\n    return OK;\n}\n\n/* Exect a read() to return EOF */\nstatic int expect_close(ne_socket *sock)\n{\n    ssize_t n = ne_sock_read(sock, buffer, 1);\n    ONV(n > 0, (\"read got %\" NE_FMT_SSIZE_T \" bytes not closure\", n));\n    ONV(n < 0 && n != NE_SOCK_CLOSED,\n\t(\"read got error not closure: `%s'\", ne_sock_error(sock)));\n    return OK;\n}\n\nstatic int good_close(ne_socket *sock)\n{\n    NE_DEBUG(NE_DBG_SOCKET, \"Socket error was %s\\n\", ne_sock_error(sock));\n    ONN(\"close failed\", ne_sock_close(sock));\n    return OK;    \n}\n\n/* Finish a test, closing socket and rejoining child. If eof is non-zero,\n * expects to read EOF from the socket before closing. */\nstatic int finish(ne_socket *sock, int eof)\n{\n    if (eof)\n\tCALL(expect_close(sock));\n    else\n\tne_sock_shutdown(sock, NE_SOCK_SEND);\n    CALL(good_close(sock));\n    return await_server();\n}\n\n/* Exect a ne_sock_peek() to return EOF */\nstatic int expect_peek_close(ne_socket *sock)\n{\n    ssize_t n = ne_sock_read(sock, buffer, 1);\n    ONV(n != NE_SOCK_CLOSED, (\"peek gave %\" NE_FMT_SSIZE_T \" not closure\", n));\n    return OK;\n}\n\n/* Test that just does a connect then a close. */\nstatic int read_close(void)\n{\n    ne_socket *sock;\n\n    CALL(begin(&sock, serve_close, NULL));\n    CALL(expect_close(sock));    \n    ONN(\"close failed\", ne_sock_close(sock));\n    return await_server();\n}\n\n/* Test that just does an open then a close. */\nstatic int open_close(void)\n{\n    ONN(\"close of newly opened socket failed\", ne_sock_close(ne_sock_create()));\n\n    return OK;\n}\n\n/* Test that just does a connect then a close (but gets the close via\n * ne_sock_peek). */\nstatic int peek_close(void)\n{\n    ne_socket *sock;\n\n    CALL(begin(&sock, serve_close, NULL));\n    CALL(expect_peek_close(sock));    \n    ONN(\"close failed\", ne_sock_close(sock));\n    return await_server();\n}\n\n/* Don't change this string. */\n#define STR \"Hello, World.\"\n\n/* do a sock_peek() on sock for 'len' bytes, and expect 'str'. */\nstatic int peek_expect(ne_socket *sock, const char *str, size_t len)\n{\n    ssize_t ret;\n    memset(buffer, '@', sizeof buffer);\n    ret = ne_sock_peek(sock, buffer, len);\n    ONV((ssize_t)len != ret, \n\t(\"peek got %\" NE_FMT_SSIZE_T \" bytes not %\" NE_FMT_SIZE_T, ret, len));\n    ONV(memcmp(str, buffer, len),\n\t(\"peek mismatch: `%.*s' not `%.*s'\", \n\t (int)len, buffer, (int)len, str));\n    ONV(buffer[len] != '@',\n        (\"buffer overrun: %\" NE_FMT_SSIZE_T \"nth byte was '%c' not '@'\", \n         len, buffer[len]));\n    return OK;\n}\n\n/* do a sock_read() on sock for 'len' bytes, and expect 'str'. */\nstatic int read_expect(ne_socket *sock, const char *str, size_t len)\n{\n    ssize_t ret = ne_sock_read(sock, buffer, len);\n    ONV((ssize_t)len != ret,\n\t(\"read got %\" NE_FMT_SSIZE_T \" bytes (%s) not %\" NE_FMT_SIZE_T,\n         ret, ne_sock_error(sock), len));\n    ONV(memcmp(str, buffer, len),\n\t(\"read mismatch: `%.*s' not `%.*s'\", \n\t (int)len, buffer, (int)len, str));    \n    return OK;\n}\n\n/* do a sock_read() on sock for 'len' bytes, and expect 'str'. */\nstatic int fullread_expect(ne_socket *sock, const char *str, size_t len)\n{\n    ssize_t ret = ne_sock_fullread(sock, buffer, len);\n    ONV(ret, (\"fullread failed (%\" NE_FMT_SSIZE_T \"): %s\", \n              ret, ne_sock_error(sock)));\n    ONV(memcmp(str, buffer, len),\n\t(\"fullread mismatch: `%.*s' not `%.*s'\", \n\t (int)len, buffer, (int)len, str));    \n    return OK;\n}\n\n#define FULLREAD(str) CALL(fullread_expect(sock, str, strlen(str)))\n\n/* Declare a struct string */\n#define DECL(var,str) struct string var = { str, 0 }; var.len = strlen(str)\n#define DECL_LONG(var,ch,n) struct string var; var.data = memset(ne_malloc(n), ch, n); var.len = n; \n\n/* Test a simple read. */\nstatic int single_read(void)\n{\n    ne_socket *sock;\n    DECL(hello, STR);\n\n    CALL(begin(&sock, serve_sstring, &hello));\n    CALL(read_expect(sock, STR, strlen(STR)));\n    CALL(expect_close(sock));\n    CALL(good_close(sock));\n\n    return await_server();\n}\n\n/* Test a simple peek. */\nstatic int single_peek(void)\n{\n    ne_socket *sock;\n    DECL(hello, STR);\n\n    CALL(begin(&sock, serve_sstring, &hello));\n    CALL(peek_expect(sock, STR, strlen(STR)));\n \n    return finish(sock, 0);\n}\n\n/* Test lots of 1-byte reads. */\nstatic int small_reads(void)\n{\n    ne_socket *sock;\n    char *pnt;\n    DECL(hello, STR);\n\n    CALL(begin(&sock, serve_sstring, &hello));\n\n    /* read the string byte-by-byte. */\n    for (pnt = hello.data; *pnt; pnt++) {\n\tCALL(read_expect(sock, pnt, 1));\n    }\n\n    return finish(sock, 1);\n}\n\n/* peek or read, expecting to get given string. */\n#define READ(str) CALL(read_expect(sock, str, strlen(str)))\n#define PEEK(str) CALL(peek_expect(sock, str, strlen(str)))\n\n/* Stress out the read buffer handling a little. */\nstatic int read_and_peek(void)\n{\n    ne_socket *sock;\n    DECL(hello, STR);\n\n    CALL(begin(&sock, serve_sstring, &hello));\n\n    PEEK(\"Hello\");\n    PEEK(\"Hell\");\n    PEEK(STR);\n    READ(\"He\");\n    PEEK(\"llo, \");\n    READ(\"l\");\n    PEEK(\"lo, World.\");\n    READ(\"lo, Worl\");\n    PEEK(\"d.\"); PEEK(\"d\");\n    READ(\"d.\");\n\n    return finish(sock, 1);\n}\n\n/* Read more bytes than were written. */\nstatic int larger_read(void)\n{\n    ne_socket *sock;\n    ssize_t nb;\n    DECL(hello, STR);\n\n    CALL(begin(&sock, serve_sstring, &hello));\n    \n    nb = ne_sock_read(sock, buffer, hello.len + 10);\n    ONV(nb != (ssize_t)hello.len, \n\t(\"read gave too many bytes (%\" NE_FMT_SSIZE_T \")\", nb));\n    ONN(\"read gave wrong data\", memcmp(buffer, hello.data, hello.len));\n    \n    return finish(sock, 1);\n}\n\nstatic int line_expect(ne_socket *sock, const char *line)\n{\n    ssize_t ret = ne_sock_readline(sock, buffer, BUFSIZ);\n    size_t len = strlen(line);\n    NE_DEBUG(NE_DBG_SOCKET, \" -> expected=%s -> actual=%s\", line, buffer);\n    ONV(ret == NE_SOCK_CLOSED, (\"socket closed, expecting `%s'\", line));\n    ONV(ret < 0, (\"socket error `%s', expecting `%s'\", \n\t\t  ne_sock_error(sock), line));\n    ONV((size_t)ret != len || strcmp(line, buffer),\n\t(\"readline mismatch: `%s' not `%s'\", buffer, line));\n    return OK;\n}\n\n#define LINE(x) CALL(line_expect(sock, x))\n\n#define STR2 \"Goodbye, cruel world.\"\n\nstatic int line_simple(void)\n{\n    ne_socket *sock;\n    DECL(oneline, STR \"\\n\" STR2 \"\\n\");\n\n    CALL(begin(&sock, serve_sstring, &oneline));\n    LINE(STR \"\\n\");\n    LINE(STR2 \"\\n\");\n    \n    return finish(sock, 1);\n}\n\nstatic int line_closure(void)\n{\n    ne_socket *sock;\n    ssize_t ret;\n    DECL(oneline, STR \"\\n\" \"foobar\");\n    \n    CALL(begin(&sock, serve_sstring, &oneline));\n    LINE(STR \"\\n\");\n    \n    ret = ne_sock_readline(sock, buffer, BUFSIZ);\n    ONV(ret != NE_SOCK_CLOSED, \n\t(\"readline got %\" NE_FMT_SSIZE_T \" not EOF: %s\", ret,\n         ne_sock_error(sock)));\n    \n    return finish(sock, 0);\n}   \n\n/* check that empty lines are handled correctly. */\nstatic int line_empty(void)\n{\n    ne_socket *sock;\n    DECL(oneline, \"\\n\\na\\n\\n\");\n\n    CALL(begin(&sock, serve_sstring, &oneline));\n    LINE(\"\\n\"); LINE(\"\\n\");\n    LINE(\"a\\n\"); LINE(\"\\n\");\n    \n    return finish(sock, 1);\n}\n\nstatic int line_toolong(void)\n{\n    ne_socket *sock;\n    ssize_t ret;\n    DECL(oneline, \"AAAAAA\\n\");\n\n    CALL(begin(&sock, serve_sstring, &oneline));\n    ret = ne_sock_readline(sock, buffer, 5);\n    ONV(ret != NE_SOCK_ERROR, \n\t(\"readline should fail on long line: %\" NE_FMT_SSIZE_T, ret));\n    reap_server();\n    ne_sock_close(sock);\n    return OK;\n}\n\n#define OVERLEN (9000)\n\nstatic int line_overflow(void)\n{\n    ne_socket *sock;\n    ssize_t ret;\n    DECL_LONG(line, 'A', OVERLEN);\n\n    CALL(begin(&sock, serve_sstring, &line));\n\n    PEEK(\"A\"); /* fill the read buffer */\n    ret = ne_sock_readline(sock, buffer, OVERLEN);\n    ONV(ret != NE_SOCK_ERROR,\n        (\"readline should fail on overlong line: %\" NE_FMT_SSIZE_T, ret));\n\n    ne_free(line.data);\n    return finish(sock, 0);\n}\n\n\n/* readline()s mingled with other operations: buffering tests. */\nstatic int line_mingle(void)\n{\n    ne_socket *sock;\n    DECL(oneline, \"alpha\\nbeta\\ndelta\\ngamma\\n\");\n\n    CALL(begin(&sock, serve_sstring, &oneline));\n    \n    READ(\"a\"); LINE(\"lpha\\n\");\n    READ(\"beta\"); LINE(\"\\n\");\n    PEEK(\"d\"); PEEK(\"delt\");\n    LINE(\"delta\\n\");\n    READ(\"gam\"); LINE(\"ma\\n\");\n    \n    return finish(sock, 1);\n}\n\n/* readline which needs multiple read() calls. */\nstatic int line_chunked(void)\n{\n    ne_socket *sock;\n    DECL(oneline, \"this is a line\\n\");\n\n    CALL(begin(&sock, serve_sstring_slowly, &oneline));\n    \n    LINE(\"this is a line\\n\");\n    \n    return finish(sock, 1);\n}\n\nstatic int line_long_chunked(void)\n{\n    ne_socket *sock;\n    ssize_t ret;\n    DECL_LONG(line, 'Z', OVERLEN);\n\n    CALL(begin(&sock, serve_sstring_slowly, &line));\n    \n    FULLREAD(\"ZZZZZZZZ\"); /* fill the buffer */\n    ret = ne_sock_readline(sock, buffer, sizeof buffer);\n    ONV(ret != NE_SOCK_ERROR,\n        (\"readline gave %\" NE_FMT_SSIZE_T \" not failure\", ret));\n\n    reap_server();\n    ne_sock_close(sock);\n    ne_free(line.data);\n    return OK;\n}\n\n\nstatic time_t to_start, to_finish;\n\nstatic int to_begin(ne_socket **sock)\n{\n    CALL(begin(sock, sleepy_server, NULL));\n    ne_sock_read_timeout(*sock, 1);\n    to_start = time(NULL);\n    return OK;\n}\n\nstatic int to_end(ne_socket *sock)\n{\n    to_finish = time(NULL);\n    reap_server(); /* hopefully it's hung. */\n    ONN(\"timeout ignored, or very slow machine\", to_finish - to_start > 3);\n    ONN(\"close failed\", ne_sock_close(sock));\n    return OK;\n}\n\t \n#define TO_BEGIN ne_socket *sock; CALL(to_begin(&sock))\n#define TO_OP(x) do { int to_ret = (x); \\\n        ONV(to_ret != NE_SOCK_TIMEOUT, (\"operation did not timeout: got %d (%s)\", to_ret, ne_sock_error(sock))); \\\n} while (0)\n#define TO_FINISH return to_end(sock)\n\n#ifndef TEST_CONNECT_TIMEOUT\n#define TEST_CONNECT_TIMEOUT 0\n#endif\n#if TEST_CONNECT_TIMEOUT\n\n/* No obvious way to reliably test a connect() timeout.  But\n * www.example.com seems to drop packets on ports other than 80 so\n * that actually works pretty well.  Disabled by default. */\nstatic int connect_timeout(void)\n{\n    static const unsigned char example_dot_com[] = \"\\xC0\\x00\\x22\\xA6\";\n    ne_socket *sock = ne_sock_create();\n    ne_inet_addr *ia = ne_iaddr_make(ne_iaddr_ipv4, example_dot_com);\n\n    ne_sock_connect_timeout(sock, 1);\n\n    TO_OP(ne_sock_connect(sock, ia, 8080));\n\n    ne_iaddr_free(ia);\n    ne_sock_close(sock);\n\n    return OK;\n}\n#endif\n\nstatic int peek_timeout(void)\n{\n    TO_BEGIN;\n    TO_OP(ne_sock_peek(sock, buffer, 1));\n    TO_FINISH;\n}\n\nstatic int read_timeout(void)\n{\n    TO_BEGIN;\n    TO_OP(ne_sock_read(sock, buffer, 1));\n    TO_FINISH;\n}\n\nstatic int readline_timeout(void)\n{\n    TO_BEGIN;\n    TO_OP(ne_sock_readline(sock, buffer, 1));\n    TO_FINISH;\n}\n\nstatic int fullread_timeout(void)\n{\n    TO_BEGIN;\n    TO_OP(ne_sock_fullread(sock, buffer, 1));\n    TO_FINISH;\n}   \n\nstatic int serve_expect(ne_socket *sock, void *ud)\n{\n    struct string *str = ud;\n    ssize_t ret;\n\n    while (str->len && \n\t   (ret = ne_sock_read(sock, buffer, sizeof(buffer))) > 0) {\n\tNE_DEBUG(NE_DBG_SOCKET, \"Got %\" NE_FMT_SSIZE_T \" bytes.\\n\", ret);\n\tONV(memcmp(str->data, buffer, ret),\n\t    (\"unexpected data: [%.*s] not [%.*s]\", \n\t     (int)ret, buffer, (int)ret, str->data));\n\tstr->data += ret;\n\tstr->len -= ret;\n\tNE_DEBUG(NE_DBG_SOCKET, \"%\" NE_FMT_SIZE_T \" bytes left.\\n\", str->len);\n    }\n\n    NE_DEBUG(NE_DBG_SOCKET, \"All data read.\\n\");\n    return OK;\n}\n\n#define WRITEL(str) CALL(full_write(sock, str, strlen(str))); \\\nminisleep()\n\nstatic int small_writes(void)\n{\n    ne_socket *sock;\n    DECL(str, \"This\\nIs\\nSome\\nText.\\n\");\n    \n    CALL(begin(&sock, serve_expect, &str));\n    \n    WRITEL(\"This\\n\"); WRITEL(\"Is\\n\"); WRITEL(\"Some\\n\"); WRITEL(\"Text.\\n\");\n    \n    return finish(sock, 1);\n}\n\nstatic int large_writes(void)\n{\n#define LARGE_SIZE (123456)\n    struct string str;\n    ne_socket *sock;\n    ssize_t n;\n\n    str.data = ne_malloc(LARGE_SIZE);\n    str.len = LARGE_SIZE;\n\n    for (n = 0; n < LARGE_SIZE; n++)\n\tstr.data[n] = 41 + n % 130;\n    \n    CALL(begin(&sock, serve_expect, &str));\n    CALL(full_write(sock, str.data, str.len));\n    \n    ne_free(str.data);\n    return finish(sock, 1);    \n}\n\nstatic int full_writev(ne_socket *sock, struct ne_iovec *vec, int count)\n{\n    int ret = ne_sock_fullwritev(sock, vec, count);\n    NE_DEBUG(NE_DBG_SOCKET, \"wrote vector (%d)\\n\", count);\n    ONV(ret, (\"writev failed (%d): %s\", ret, ne_sock_error(sock)));\n    return OK;\n}\n\n#undef LARGE_SIZE\n#define LARGE_SIZE (123456 * 4)\n\nstatic int large_writev(void)\n{\n    struct string str;\n    ne_socket *sock;\n    ssize_t n;\n    struct ne_iovec vec[4];\n\n    str.data = ne_malloc(LARGE_SIZE);\n    str.len = LARGE_SIZE;\n\n    for (n = 0; n < LARGE_SIZE; n++)\n\tstr.data[n] = 41 + n % 130;\n    \n    for (n = 0; n < 4; n++) {\n        vec[n].base = str.data + n * LARGE_SIZE / 4;\n        vec[n].len = LARGE_SIZE / 4;\n    }\n\n    CALL(begin(&sock, serve_expect, &str));\n    CALL(full_writev(sock, vec, 4));\n    \n    ne_free(str.data);\n    return finish(sock, 1);    \n}\n\n\n/* echoes back lines. */\nstatic int echo_server(ne_socket *sock, void *ud)\n{\n    ssize_t ret;\n\n    while ((ret = ne_sock_readline(sock, buffer, sizeof(buffer))) > 0) {\n\tNE_DEBUG(NE_DBG_SOCKET, \"Line: %s\", buffer);\n\tONN(\"write failed\", ne_sock_fullwrite(sock, buffer, ret));\n\tNE_DEBUG(NE_DBG_SOCKET, \"Wrote line.\\n\");\n    }\n\n    ONV(ret != NE_SOCK_CLOSED, (\"unexpected readline failure: %s\",\n\t\t\t\tne_sock_error(sock)));\n\n    NE_DEBUG(NE_DBG_SOCKET, \"ssl: Readline got closure\\n\");\n\n    return 0;\n}\n\nstatic int echo_expect(ne_socket *sock, const char *line)\n{\n    CALL(full_write(sock, line, strlen(line)));\n    return line_expect(sock, line);\n}\n\n#define ECHO(line) CALL(echo_expect(sock, line))\n\nstatic int echo_lines(void)\n{\n    ne_socket *sock;\n    CALL(begin(&sock, echo_server, NULL));\n    ECHO(\"hello,\\n\");\n    ECHO(\"\\n\");\n    ECHO(\"world\\n\");\n    return finish(sock, 0);\n}\n\n#ifdef SOCKET_SSL\nstatic int serve_wait_close(ne_socket *sock, void *ud)\n{\n    ONV(ne_sock_read(sock, buffer, 1) != NE_SOCK_CLOSED,\n        (\"failed waiting for TLS closure: %s\", ne_sock_error(sock)));\n\n    return 0;\n}\n\nstatic int ssl_shutdown(void)\n{\n    ne_socket *sock;\n    int ret;\n\n    CALL(begin(&sock, serve_wait_close, NULL));\n\n    ONV(ne_sock_shutdown(sock, NE_SOCK_RECV) != NE_SOCK_RETRY,\n        (\"TLS socket closed too early\"));\n\n    ret = ne_sock_shutdown(sock, NE_SOCK_SEND);\n    if (ret == NE_SOCK_RETRY) {\n        /* Wait for closure. */\n        ret = ne_sock_read(sock, buffer, 0);\n        ONV(ret != NE_SOCK_CLOSED,\n            (\"read for closure didn't get closure: %d/%s\",\n             ret, ne_sock_error(sock)));\n    }\n    else {\n        ONV(ret, (\"socket shutdown unexpected state: %d/%s\",\n                  ret, ne_sock_error(sock)));\n    }\n\n    CALL(await_server());\n    ne_sock_close(sock);\n\n    return OK;\n}\n\nstatic int ssl_closure(void)\n{\n    ne_socket *sock;\n    ssize_t ret;\n    CALL(begin(&sock, serve_close, NULL));\n    CALL(full_write(sock, \"a\", 1));\n    ne_sock_shutdown(sock, NE_SOCK_SEND);\n    CALL(await_server());\n    do {\n        ret = ne_sock_fullwrite(sock, \"a\", 1);\n    } while (ret == 0);\n    ONV(ret != NE_SOCK_RESET && ret != NE_SOCK_CLOSED, \n\t(\"write got %\" NE_FMT_SSIZE_T \" not reset or closure: %s\", ret,\n         ne_sock_error(sock)));\n    ne_sock_close(sock);\n    return OK;\n}\n\nstatic int serve_truncate(ne_socket *sock, void *userdata)\n{\n    if (ne_sock_read(sock, buffer, 1) != 1)\n        NE_DEBUG(NE_DBG_SOCKET, \"serve_truncate failed to read a byte.\\n\");\n    NE_DEBUG(NE_DBG_SOCKET, \"read a byte, exiting...\\n\");\n    exit(0);\n}\n\n/* when an EOF is received without a clean shutdown (close_notify\n   message). */\nstatic int ssl_truncate(void)\n{\n    ne_socket *sock; int ret;\n    \n    CALL(begin(&sock, serve_truncate, NULL));\n    CALL(full_write(sock, \"a\", 1));\n    ret = ne_sock_read(sock, buffer, 1);\n    ONV(ret != NE_SOCK_TRUNC,\n\t(\"socket got error %d not truncation: `%s'\", ret,\n\t ne_sock_error(sock)));\n    ne_sock_close(sock);\n    CALL(await_server());\n    return OK;\n}\n\n#else\n\n/* use W Richard Stevens' SO_LINGER trick to elicit a TCP RST */\nstatic int serve_reset(ne_socket *sock, void *ud)\n{\n    ONV(ne_sock_read(sock, buffer, 1) != 1,\n\t(\"socket read error `%s'\", ne_sock_error(sock)));\n    ONV(buffer[0] != 'R',\n        (\"got unexpected byte %c from client\", buffer[0]));\n    reset_socket(sock);\n    exit(0);\n    return 0;\n}\n\nstatic int write_reset(void)\n{\n    ne_socket *sock;\n    int ret;\n    CALL(begin(&sock, serve_reset, NULL));\n    CALL(full_write(sock, \"R\", 1));\n    CALL(await_server());\n    ret = ne_sock_fullwrite(sock, \"a\", 1);\n    if (ret == 0) {\n        ne_sock_close(sock);\n        return SKIP;\n    }\n    if (ret == NE_SOCK_CLOSED) {\n        t_warning(\"got EOF, failed to elicit TCP RST\");\n    } else {\n        ONV(ret != NE_SOCK_RESET, \n            (\"write got %d not reset: %s\", ret, ne_sock_error(sock)));\n    }\n    return good_close(sock);\n}\n\nstatic int read_reset(void)\n{\n    ne_socket *sock;\n    ssize_t ret;\n    CALL(begin(&sock, serve_reset, NULL));\n    CALL(full_write(sock, \"R\", 1));\n    CALL(await_server());\n    ret = ne_sock_read(sock, buffer, 1);\n    if (ret == NE_SOCK_CLOSED) {\n        ne_sock_close(sock);\n        return SKIP;\n    }\n    ONV(ret != NE_SOCK_RESET, \n        (\"read got %\" NE_FMT_SSIZE_T \" not reset: %s\", ret,\n         ne_sock_error(sock)));\n    return good_close(sock);\n}    \n#endif\n\nstatic int expect_block_timeout(ne_socket *sock, int timeout, const char *msg)\n{\n    int ret;\n    NE_DEBUG(NE_DBG_SOCKET, \"blocking for %d\\n\", timeout);\n    ret = ne_sock_block(sock, timeout);\n    ONV(ret != NE_SOCK_TIMEOUT, (\n            \"ne_sock_block got %d not timeout: %s\", ret, msg));\n    return OK;\n}\n\nstatic int blocking(void)\n{\n    ne_socket *sock;\n    int ret;\n    \n    CALL(begin(&sock, echo_server, NULL));\n    CALL(expect_block_timeout(sock, 1, \"with non-zero timeout\"));\n         \n    WRITEL(\"Hello, world.\\n\");\n    \n    /* poll for data */\n    do {\n        ret = ne_sock_block(sock, 1);\n    } while (ret == NE_SOCK_TIMEOUT);\n\n    ONV(ret != 0, (\"ne_sock_block never got data: %d\", ret));\n\n    PEEK(\"Hello,\");\n    ret = ne_sock_block(sock, 1);\n    ONV(ret != 0, (\"ne_sock_block failed after peek: %d\", ret));\n\n    LINE(\"Hello, world.\\n\");\n\n    return finish(sock, 0);\n}\n\nstatic int block_timeout(void)\n{\n    TO_BEGIN;\n    TO_OP(ne_sock_block(sock, 1));\n    TO_FINISH;\n}\n\n#ifndef SOCKET_SSL\n/* Waits for EOF from read-side and then sends \"abcd\". */\nstatic int serve_shutdown(ne_socket *sock, void *userdata)\n{\n    ONV(ne_sock_read(sock, buffer, 1) != NE_SOCK_CLOSED,\n        (\"expected to get closure\"));\n    CALL(full_write(sock, \"abcd\", 4));\n    return 0;\n}\n\nstatic int bidi(void)\n{\n    ne_socket *sock;\n    \n    CALL(begin(&sock, serve_shutdown, NULL));\n\n    CALL(expect_block_timeout(sock, 1, \"read should timeout before closure\"));\n\n    ONV(ne_sock_shutdown(sock, NE_SOCK_SEND) != 0,\n\t(\"shutdown failed: `%s'\", ne_sock_error(sock)));\n    FULLREAD(\"abcd\");\n\n    return finish(sock, 1);\n}\n#endif\n\nstatic int ssl_session_id(void)\n{\n    ne_socket *sock;\n    unsigned char buf[128];\n    size_t len1;\n\n    CALL(begin(&sock, echo_server, NULL));\n\n    ECHO(\"hello, session ID test case!\\n\");\n\n#ifdef SOCKET_SSL\n    len1 = 0;\n    ONN(\"retrieve session id length\",\n        ne_sock_sessid(sock, NULL, &len1));\n\n    if (len1 == 0) {\n        /* recent versions of OpenSSL seem to do this, not sure\n         * why or whether it's bad. */\n        finish(sock, 1);\n        t_context(\"zero-length session ID, cannot test further\");\n        return SKIP;\n    }            \n\n    if (len1 < sizeof buf) {\n        buf[len1] = 'Z';\n    }\n    \n    {\n        size_t len2;\n\n        len2 = sizeof buf;\n        ONN(\"could not retrieve session id\",\n            ne_sock_sessid(sock, buf, &len2));\n        \n        ONN(\"buffer size changed!?\", len1 != len2);\n    }        \n\n    ONN(\"buffer written past expected end\", \n        len1 < sizeof buf && buf[len1] != 'Z');\n\n    /* Attempt retrieval into too-short buffer: */\n    len1 = 0;\n    ONN(\"success for buffer overflow case\",\n        ne_sock_sessid(sock, buf, &len1) == 0);\n\n#else\n    len1 = sizeof buf;\n    ONN(\"retrieved session id for non-SSL socket!?\",\n        ne_sock_sessid(sock, buf, &len1) == 0);\n#endif\n\n    ne_sock_close(sock);\n    return await_server();\n}\n\nstatic int serve_ppeer(ne_socket *sock, void *ud)\n{\n    unsigned int port = 99999;\n    ne_inet_addr *ia = ne_sock_peer(sock, &port);\n    char buf[128], line[256];\n\n    if (ia == NULL)\n        ne_snprintf(line, sizeof line, \"error: %s\", ne_sock_error(sock));\n    else\n        ne_snprintf(line, sizeof line,\n                    \"%s@%u\\n\", ne_iaddr_print(ia, buf, sizeof buf),\n                    port);\n\n    CALL(full_write(sock, line, strlen(line)));\n         \n    ne_iaddr_free(ia);\n    \n    return OK;\n}\n\nstatic int try_prebind(int addr, int port)\n{\n    ne_socket *sock = ne_sock_create();\n    ne_inet_addr *ia;\n    char buf[128], line[256];\n    unsigned int srvport;\n\n    ia = get_lh_inet_addr();\n    ONN(\"ne_iaddr_make returned NULL\", ia == NULL);\n    \n    CALL(new_spawn_server(1, serve_ppeer, NULL, &srvport));\n\n    ne_sock_prebind(sock, addr ? ia : NULL, port ? 7778 : 0);\n\n    ONN(\"could not connect\", ne_sock_connect(sock, ia, srvport));\n\n    ne_snprintf(line, sizeof line,\n                \"%s@%d\\n\", ne_iaddr_print(ia, buf, sizeof buf),\n                7778);\n    \n    if (!port) {\n        /* Don't know what port will be chosen, so... */\n        ssize_t ret = ne_sock_readline(sock, buffer, BUFSIZ);\n        \n        ONV(ret < 0, (\"socket error `%s'\", ne_sock_error(sock)));\n\n        ONV(strncmp(line, buffer, strchr(line, '@') - line) != 0,\n            (\"bad address: '%s', expecting '%s'\",\n             buffer, line));\n    }\n    else {\n        LINE(line);\n    }\n\n    ne_sock_close(sock);\n    CALL(await_server());\n\n    ne_iaddr_free(ia);\n    return OK;\n}\n\nstatic int prebind(void)\n{\n    CALL(try_prebind(1, 0));\n    CALL(try_prebind(0, 1));\n    CALL(try_prebind(1, 1));\n\n    return OK;\n}\n\nstatic int serve_cipher(ne_socket *sock, void *ud)\n{\n    char *ciph = ne_sock_cipher(sock);\n    char *s = ciph && strlen(ciph) ? ciph : \"NULL\";\n\n    CALL(full_write(sock, s, strlen(s)));\n\n    if (ciph) ne_free(ciph);\n    \n    return OK;\n}\n\nstatic int cipher(void)\n{\n    ne_socket *sock;\n\n#ifdef SOCKET_SSL\n    char *ciph;\n\n    CALL(begin(&sock, serve_cipher, NULL));\n\n    ciph = ne_sock_cipher(sock);\n\n    ONN(\"NULL/empty cipher\", ciph == NULL || strlen(ciph) == 0);\n\n    FULLREAD(ciph);\n    \n    ne_free(ciph);\n    \n#else\n    CALL(begin(&sock, serve_cipher, NULL));\n\n    ONN(\"non-NULL cipher for non-SSL socket\", \n        ne_sock_cipher(sock) != NULL);\n\n    FULLREAD(\"NULL\");\n\n#endif\n    return finish(sock, 1);\n}\n\nstatic int protocols(void)\n{\n    ne_socket *sock;\n    enum ne_ssl_protocol proto;\n\n    CALL(begin(&sock, serve_close, NULL));\n\n    proto = ne_sock_getproto(sock);\n#ifdef SOCKET_SSL\n    ONN(\"protocol should be set\", proto == NE_SSL_PROTO_UNSPEC);\n#else\n    ONN(\"protocol should be unset\", proto != NE_SSL_PROTO_UNSPEC);\n#endif\n\n    return finish(sock, 1);\n}\n\n#ifdef SOCKET_SSL\nstatic int serve_protocol(ne_socket *sock, void *ud)\n{\n    enum ne_ssl_protocol proto = ne_sock_getproto(sock);\n    const char *name = ne_ssl_proto_name(proto);\n\n    WRITEL(\"protocol\\n\");\n    WRITEL(name);\n    WRITEL(\"\\n\");\n\n    return 0;\n}\n\nstatic int proto_tls12(void)\n{\n    ne_socket *sock;\n    enum ne_ssl_protocol proto;\n\n    CALL(beginc(&sock, client_ctx_tls12, serve_protocol, NULL));\n\n    proto = ne_sock_getproto(sock);\n    NE_DEBUG(NE_DBG_SOCKET, \"protocol: %d\\n\", proto);\n\n    FULLREAD(\"protocol\\n\");\n    FULLREAD(\"TLSv1.2\\n\");\n\n    return finish(sock, 1);\n}\n\nstatic int context_untrusted(void)\n{\n    ne_ssl_context *ctx = ne_ssl_context_create(NE_SSL_CTX_CLIENT);\n    ne_socket *sock;\n\n    ONN(\"SSL_CTX_new failed for notrust client\", ctx == NULL);\n\n    CALL(beginc(&sock, ctx, serve_close, NULL));\n    CALL(finish(sock, 1));\n\n    ne_ssl_context_destroy(ctx);\n\n    return OK;\n}\n#endif\n\nstatic int error(void)\n{\n    ne_socket *sock = ne_sock_create();\n\n    ne_sock_set_error(sock, \"%s:%s\", \"fish\", \"42\");\n    \n    ONCMP(\"fish:42\", ne_sock_error(sock), \"socket error\", \"set\");\n\n    ne_sock_close(sock);\n    return OK;\n}\n\nstatic int begin_socks(ne_socket **sock, struct socks_server *srv,\n                       server_fn server, void *userdata)\n{\n    unsigned int port;\n    srv->server = server;\n    srv->userdata = userdata;\n    srv->say_hello = 1;\n    CALL(new_spawn_server(1, socks_server, srv, &port));\n    return do_connect(sock, localhost, port);\n}\n\nstatic int socks_proxy(void)\n{\n    static const struct {\n        enum ne_sock_sversion version;\n        int addr;\n        const char *fqdn;\n        unsigned int port;\n        const char *username, *password;\n    } ts[] = {\n        { NE_SOCK_SOCKSV4, 4, NULL, 55555, NULL, NULL },\n        { NE_SOCK_SOCKSV4, 4, NULL, 55555, \"foobar\", NULL },\n        { NE_SOCK_SOCKSV4A, 0, \"www.example.com\", 55555, NULL, NULL },\n        { NE_SOCK_SOCKSV5, 0, \"www.example.com\", 55555, NULL, NULL },\n        { NE_SOCK_SOCKSV5, 4, NULL, 55555, NULL, NULL },\n#ifdef TEST_IPV6\n        { NE_SOCK_SOCKSV5, 6, NULL, 55555, NULL, NULL },\n#endif\n        { NE_SOCK_SOCKSV5, 0, \"www.example.com\", 55555, \"norman\", \"foobar\" }\n    };\n    unsigned n;\n\n    for (n = 0; n < sizeof(ts)/sizeof(ts[n]); n++) {\n        ne_socket *sock;\n        struct socks_server arg = {0};\n        int ret;\n\n        arg.version = ts[n].version;\n        arg.expect_port = ts[n].port;\n        if (ts[n].addr == 4)\n            arg.expect_addr = ne_iaddr_make(ne_iaddr_ipv4, raw_127);\n#ifdef TEST_IPV6\n        else if (ts[n].addr == 6)\n            arg.expect_addr = ne_iaddr_make(ne_iaddr_ipv4, raw6_cafe);\n#endif\n        else\n            arg.expect_fqdn = ts[n].fqdn;\n        arg.username = ts[n].username;\n        arg.password = ts[n].password;\n        \n        CALL(begin_socks(&sock, &arg, echo_server, NULL));\n\n        ret = ne_sock_proxy(sock, ts[n].version, arg.expect_addr, \n                            ts[n].fqdn, ts[n].port,\n                            ts[n].username, ts[n].password);\n        ONV(ret, (\"proxy connect #%u gave %d\", n, ret));\n        FULLREAD(\"ok!\\n\");\n        ECHO(\"hello,\\n\");\n        ECHO(\"\\n\");\n        ECHO(\"world\\n\");\n        \n        if (ts[n].addr)\n            ne_iaddr_free(arg.expect_addr);\n\n        CALL(finish(sock, 0));\n    }\n\n    return OK;\n}\n\nstatic int fail_socks(void)\n{\n    static const struct {\n        enum ne_sock_sversion version;\n        enum socks_failure failure;\n        const char *expect;\n        const char *username, *password;\n    } ts[] = {\n        { NE_SOCK_SOCKSV5, fail_init_vers, \n          \"Invalid version in proxy response\", NULL, NULL },\n        { NE_SOCK_SOCKSV5, fail_init_trunc,\n          \"Could not read initial response from proxy: Connection closed\",\n          NULL, NULL },\n        { NE_SOCK_SOCKSV5, fail_init_close, \n          \"Could not read initial response from proxy: Connection closed\", \n          NULL, NULL },\n        { NE_SOCK_SOCKSV5, fail_no_auth, \n          \"No acceptable authentication method\",\n          NULL, NULL },\n        { NE_SOCK_SOCKSV5, fail_bogus_auth, \n          \"Unexpected authentication method chosen\",\n          NULL, NULL },\n        { NE_SOCK_SOCKSV5, fail_auth_close, \n          \"Could not read login reply: Connection closed\",\n          \"foo\", \"bar\" },\n        { NE_SOCK_SOCKSV5, fail_auth_denied, \n          \"Authentication failed\", \"foo\", \"bar\" }\n    };\n    unsigned n;\n\n    for (n = 0; n < sizeof(ts)/sizeof(ts[n]); n++) {\n        ne_socket *sock;\n        struct socks_server arg = {0};\n        int ret;\n\n        arg.version = ts[n].version;\n        arg.failure = ts[n].failure;\n        arg.expect_port = 5555;\n        arg.expect_addr = ne_iaddr_make(ne_iaddr_ipv4, raw_127);\n        arg.username = ts[n].username;\n        arg.password = ts[n].password;\n        \n        CALL(begin_socks(&sock, &arg, echo_server, NULL));\n\n        ret = ne_sock_proxy(sock, ts[n].version, arg.expect_addr, \n                            NULL, arg.expect_port,\n                            ts[n].username, ts[n].password);\n        ONV(ret == 0, \n            (\"proxy connect #%u succeeded, expected failure '%s'\", n, \n             ts[n].expect));\n        \n        if (ret != 0 && strstr(ne_sock_error(sock), ts[n].expect) == NULL) {\n            t_warning(\"proxy connect #%u got unexpected failure '%s', wanted '%s'\",\n                      n, ne_sock_error(sock), ts[n].expect);\n        }    \n\n        ne_iaddr_free(arg.expect_addr);\n\n        CALL(finish(sock, 0));\n    }\n\n    return OK;\n}\n\nstatic int scopes(void)\n{\n    ne_inet_addr *ia;\n\n#ifdef TEST_IPV6\n    ia = ne_iaddr_parse(\"fe80::cafe\", ne_iaddr_ipv6);\n#else\n    ia = ne_iaddr_parse(\"127.0.0.1\", ne_iaddr_ipv4);\n#endif\n\n    (void) ne_iaddr_set_scope(ia, \"foobar\");\n    (void) ne_iaddr_get_scope(ia);\n\n    ne_iaddr_free(ia);\n    \n    return OK;\n}\n\nne_test tests[] = {\n    T(multi_init),\n    T_LEAKY(resolve),\n    T(resolve_numeric),\n#ifdef SOCKET_SSL\n    T_LEAKY(init_ssl),\n#endif\n    T(addr_make_v4),\n    T(parse_v4),\n    T(addr_make_v6),\n    T(addr_compare),\n    T(addr_put),\n    T(addr_reverse),\n    T(just_connect),\n    T(addr_connect),\n    T(addr_peer),\n    T(addr_canonical),\n    T(addr_failures),\n    T(read_close),\n    T(peek_close),\n    T(open_close),\n    T(single_read),\n    T(single_peek),\n    T(small_reads),\n    T(read_and_peek),\n    T(larger_read),\n    T(ssl_session_id),\n    T(cipher),\n    T(protocols),\n#ifdef SOCKET_SSL\n    T(proto_tls12),\n    T(context_untrusted),\n#endif\n    T(line_simple),\n    T(line_closure),\n    T(line_empty),\n    T(line_toolong),\n    T(line_overflow),\n    T(line_mingle),\n    T(line_chunked),\n    T(line_long_chunked),\n    T(small_writes),\n    T(large_writes),\n    T(large_writev),\n    T(echo_lines),\n    T(blocking),\n    T(prebind),\n    T(error),\n#ifdef SOCKET_SSL\n    T(ssl_shutdown),\n    T(ssl_closure),\n    T(ssl_truncate),\n#else\n    T(write_reset),\n    T(read_reset),\n    T(bidi),\n#endif\n#if TEST_CONNECT_TIMEOUT\n    T(connect_timeout),\n#endif\n    T(read_timeout),\n    T(peek_timeout),\n    T(readline_timeout),\n    T(fullread_timeout),\n    T(block_timeout),\n    T(socks_proxy),\n    T(fail_socks),\n    T(scopes),\n    T(NULL)\n};\n"
  },
  {
    "path": "test/ssl.c",
    "content": "/* \n   neon test suite\n   Copyright (C) 2002-2026, Joe Orton <joe@manyfish.co.uk>\n\n   This program is free software; you can redistribute it and/or modify\n   it under the terms of the GNU General Public License as published by\n   the Free Software Foundation; either version 2 of the License, or\n   (at your option) any later version.\n  \n   This program is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU General Public License for more details.\n  \n   You should have received a copy of the GNU General Public License\n   along with this program; if not, write to the Free Software\n   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\n*/\n\n#include \"config.h\"\n\n#include <sys/types.h>\n\n#include <sys/stat.h>\n\n#ifdef HAVE_STDLIB_H\n#include <stdlib.h>\n#endif\n#ifdef HAVE_UNISTD_H\n#include <unistd.h>\n#endif\n#include <errno.h>\n\n#include \"ne_request.h\"\n#include \"ne_socket.h\"\n#include \"ne_ssl.h\"\n#include \"ne_auth.h\"\n\n#include \"tests.h\"\n#include \"child.h\"\n#include \"utils.h\"\n\n#ifndef NE_HAVE_SSL\n/* this file shouldn't be built if SSL is not enabled. */\n#error SSL not supported\n#endif\n\n#include \"ne_pkcs11.h\"\n\n#define SERVER_CERT \"server.cert\"\n#define CA2_SERVER_CERT \"ca2server.pem\"\n#define CA_CERT \"ca/cert.pem\"\n\n#define P12_PASSPHRASE \"foobar\"\n\n#define SERVER_DNAME \"Neon QA Dept, Neon Hackers Ltd, \" \\\n                     \"Cambridge, Cambridgeshire, GB\"\n#define CACERT_DNAME \"Random Dept, Neosign, Oakland, California, US\"\n\nstatic char *srcdir = \".\";\nstatic char *server_key = NULL; \n\nstatic ne_ssl_certificate *def_ca_cert = NULL, *def_server_cert;\nstatic ne_ssl_client_cert *def_cli_cert;\n\nstatic char *nul_cn_fn;\n\nstatic int check_dname(const ne_ssl_dname *dn, const char *expected,\n                       const char *which);\n\nstatic int check_cert_dnames(const ne_ssl_certificate *cert,\n                             const char *subject, const char *issuer)\n    ne_attribute((nonnull (2)));\n\n/* Arguments for running the SSL server */\nstruct ssl_server_args {\n    char *cert; /* the server cert to present. */\n    const char *key; /* server key filename */\n    const char *response; /* the HTTP response message to send. */\n    int numreqs; /* number of request/responses to handle over the SSL connection. */\n\n    /* client cert handling: */\n    int require_cc; /* require a client cert if non-NULL */\n    const char *ca_list; /* file of CA certs to verify client cert against */\n    int fail_silently; /* exit with success if handshake fails */\n    \n    /* session caching: */\n    int cache; /* use the session cache if non-zero */\n    struct ssl_session {\n        unsigned char id[128];\n        size_t len;\n    } session;\n    int count; /* internal use. */\n\n    /* minimum, maximum version. */\n    enum ne_ssl_protocol minver, maxver;\n};\n\n/* default response string if args->response is NULL */\n#define DEF_RESP \"HTTP/1.0 200 OK\\r\\nContent-Length: 0\\r\\n\\r\\n\"\n\n/* An SSL server inna bun. */\nstatic int ssl_server(ne_socket *sock, void *userdata)\n{\n    struct ssl_server_args *args = userdata;\n    int ret;\n    char buf[BUFSIZ];\n    const char *key;\n    static ne_ssl_context *ctx = NULL;\n\n    if (ctx == NULL) {\n        ctx = ne_ssl_context_create(NE_SSL_CTX_SERVER);\n    }\n\n    ONV(ctx == NULL, (\"could not create SSL context\"));\n\n    key = args->key ? args->key : server_key;\n    NE_DEBUG(NE_DBG_HTTP, \"SSL server init with keypair (%s, %s).\\n\",\n             args->cert, key);\n             \n    ONV(ne_ssl_context_keypair(ctx, args->cert, key),\n        (\"failed to load server keypair: ...\"));\n\n    if (args->require_cc && !args->ca_list) {\n        args->ca_list = CA_CERT;\n    }\n\n    ne_ssl_context_set_verify(ctx, args->require_cc, \n                              args->ca_list, args->ca_list);\n\n    ret = ne_sock_accept_ssl(sock, ctx);\n    if (ret && args->fail_silently) {\n        return 0;\n    }\n    ONV(ret, (\"SSL accept failed: %s\", ne_sock_error(sock)));\n\n    args->count++;\n\n    /* loop handling requests: */\n    do {\n        const char *response = args->response ? args->response : DEF_RESP;\n\n        ret = ne_sock_read(sock, buf, BUFSIZ - 1);\n        if (ret == NE_SOCK_CLOSED)\n            return 0; /* connection closed by parent; give up. */\n        ONV(ret < 0, (\"SSL read failed (%d): %s\", ret, \n                      ne_sock_error(sock)));\n        \n        buf[ret] = '\\0';\n        \n        NE_DEBUG(NE_DBG_HTTP, \"Request over SSL was: [%s]\\n\", buf);\n        \n        if (strstr(buf, \"Proxy-Authorization:\") != NULL) {\n            NE_DEBUG(NE_DBG_HTTP, \"Got Proxy-Auth header over SSL!\\n\");\n            response = \"HTTP/1.1 500 Client Leaks Credentials\\r\\n\"\n                \"Content-Length: 0\\r\\n\" \"\\r\\n\";\n        }\n        \n        ONV(ne_sock_fullwrite(sock, response, strlen(response)),\n            (\"SSL write failed: %s\", ne_sock_error(sock)));\n        \n    } while (--args->numreqs > 0);\n\n    if (args->minver || args->maxver) {\n        unsigned int vers = ne_sock_getproto(sock);\n        const char *name = ne_ssl_proto_name(vers);\n\n        NE_DEBUG(NE_DBG_HTTP, \"ssl: TLS protocol version (%d): [%s]\\n\", \n                 vers, name);\n\n        ONV((args->minver && vers < args->minver)\n            || (args->maxver && vers > args->maxver),\n            (\"SSL protocol version %d (%s) outside range (%d, %d)\",\n             vers, name, args->minver, args->maxver));\n    }\n\n    if (args->cache) {\n        unsigned char sessid[128];\n        size_t len = sizeof sessid;\n\n        ONN(\"could not retrieve session ID\",\n            ne_sock_sessid(sock, sessid, &len));\n        \n#ifdef NE_DEBUGGING\n        {\n            char *b64 = ne_base64(sessid, len);\n            NE_DEBUG(NE_DBG_SSL, \"ssl: Session id retrieved (%d): [%s]\\n\", \n                     args->count, b64);\n            ne_free(b64);\n        }\n#endif\n        \n        if (args->count == 1) {\n            /* save the session. */\n            memcpy(args->session.id, sessid, len);\n            args->session.len = len;\n        } else {\n            /* Compare with stored session. */\n            ONN(\"cached session not used\", \n                args->session.len != len\n                || memcmp(args->session.id, sessid, len));\n        }\n    }\t\n\n    ret = ne_sock_shutdown(sock, NE_SOCK_SEND);\n    NE_DEBUG(NE_DBG_SSL, \"ssl: Shutdown received %d\\n\", ret);\n    \n    return 0;\n}\n\nstatic int make_ssl_session_port(ne_session **sess,\n                                 const char *hostname, int port,\n                                 server_fn fn, void *userdata)\n{\n    return fakeproxied_session_server(sess, \"https\", hostname, port,\n                                      fn, userdata);\n}\n\nstatic int make_ssl_session(ne_session **sess, const char *hostname,\n                            server_fn fn, void *userdata)\n{\n    return make_ssl_session_port(sess,\n                                 hostname ? hostname : \"localhost\", 7777,\n                                 fn, userdata);\n}\n\n/* Runs SSL server which will accept 'count' connections, running\n * ssl_server as callback with given 'args'. */\nstatic int multi_ssl_session(int count, ne_session **sess,\n                             struct ssl_server_args *args)\n{\n    return fakeproxied_multi_session_server(count, sess, \"https\",\n                                            \"localhost\",\n                                            7777,\n                                            ssl_server, args);\n}\n\nstatic int load_and_trust_cert(ne_session *sess, const char *ca_cert)\n{\n    ne_ssl_certificate *ca = ne_ssl_cert_read(ca_cert);\n    ONV(ca == NULL, (\"could not load CA cert `%s'\", ca_cert));\n    ne_ssl_trust_cert(sess, ca);\n    ne_ssl_cert_free(ca);\n    return OK;\n}\n\nstatic int make_ssl_request(struct ssl_server_args *args,\n                            const char *ca_cert, const char *hostname,\n                            ne_ssl_verify_fn verify_fn, void *verify_ud)\n{\n    ne_session *sess;\n\n    CALL(make_ssl_session(&sess, hostname, ssl_server, args));\n\n    if (ca_cert) CALL(load_and_trust_cert(sess, ca_cert));\n    \n    if (verify_fn) ne_ssl_set_verify(sess, verify_fn, verify_ud);\n\n    CALL(any_2xx_request(sess, \"/foo\"));\n\n    return destroy_and_wait(sess);\n}\n\nstatic int init(void)\n{\n    /* take srcdir as argv[1] for VPATH builds. */\n    if (test_argc > 1) {\n        srcdir = test_argv[1];\n    }\n        \n    /* take srcdir as argv[1]. */\n    server_key = \"server.key\";\n    \n    if (ne_sock_init()) {\n\tt_context(\"could not initialize socket/SSL library.\");\n\treturn FAILHARD;\n    }\n\n    def_ca_cert = ne_ssl_cert_read(CA_CERT);\n    if (def_ca_cert == NULL) {\n        t_context(\"couldn't load CA cert %s\", CA_CERT);\n        return FAILHARD;\n    }\n\n    def_server_cert = ne_ssl_cert_read(SERVER_CERT);\n    if (def_server_cert == NULL) {\n        t_context(\"couldn't load server cert %s\", SERVER_CERT);\n        return FAILHARD;\n    }\n    \n    /* tests for the encrypted client cert, client.p12 */\n    def_cli_cert = ne_ssl_clicert_read(\"client.p12\");\n    if (def_cli_cert == NULL) {\n        t_context(\"could not load client.p12\");\n        return FAILHARD;\n    }\n\n    if (!ne_ssl_clicert_encrypted(def_cli_cert)) {\n        ne_ssl_clicert_free(def_cli_cert);\n        def_cli_cert = NULL;\n        t_context(\"client.p12 is not encrypted!?\");\n        return FAIL;\n    }\n\n    if (ne_ssl_clicert_decrypt(def_cli_cert, P12_PASSPHRASE)) {\n        ne_ssl_clicert_free(def_cli_cert);\n        def_cli_cert = NULL;\n        t_context(\"failed to decrypt client.p12\");\n        return FAIL;\n    }\n\n    nul_cn_fn = ne_concat(srcdir, \"/nulcn.pem\", NULL);\n\n    return OK;\n}\n\n/* just check the result codes of loading server certs. */\nstatic int load_server_certs(void)\n{\n    ne_ssl_certificate *cert;\n\n    cert = ne_ssl_cert_read(\"Makefile\");\n    ONN(\"invalid CA cert file loaded successfully\", cert != NULL);\n\n    cert = ne_ssl_cert_read(\"nonesuch.pem\");\n    ONN(\"non-existent 'nonesuch.pem' loaded successfully\", cert != NULL);\n\n    cert = ne_ssl_cert_read(\"ssigned.pem\");\n    ONN(\"could not load ssigned.pem\", cert == NULL);\n    ne_ssl_cert_free(cert);\n\n    return OK;\n}\n\nstatic int trust_default_ca(void)\n{\n    ne_session *sess = ne_session_create(\"https\", \"localhost\", 443);\n    ne_ssl_trust_default_ca(sess);\n    ne_session_destroy(sess);\n    return OK;\n}\n\n#define CC_NAME \"Just A Neon Client Cert\"\n\n/* Tests for loading client certificates */\nstatic int load_client_cert(void)\n{\n    ne_ssl_client_cert *cc, *cc2;\n    const ne_ssl_certificate *cert;\n    const char *name;\n\n    cc = ne_ssl_clicert_read(\"client.p12\");\n    ONN(\"could not load client.p12\", cc == NULL);\n    ONN(\"client.p12 not encrypted!?\", !ne_ssl_clicert_encrypted(cc));\n    name = ne_ssl_clicert_name(cc);\n    if (name == NULL) {\n        t_warning(\"no friendly name given\");\n    } else {\n        ONV(strcmp(name, CC_NAME), (\"friendly name was %s not %s\", name, CC_NAME));\n    }\n    ONN(\"failed to decrypt\", ne_ssl_clicert_decrypt(cc, P12_PASSPHRASE));\n    ne_ssl_clicert_free(cc);\n\n    cc = ne_ssl_clicert_read(\"client.p12\");\n    ONN(\"decrypted client.p12 with incorrect password!?\",\n        ne_ssl_clicert_decrypt(cc, \"barfoo\") == 0);\n    ne_ssl_clicert_free(cc);\n\n    /* tests for the unencrypted client cert, client2.p12 */\n    cc = ne_ssl_clicert_read(\"unclient.p12\");\n    ONN(\"could not load unencrypted cert unclient.p12\", cc == NULL);\n    ONN(\"unencrypted cert marked encrypted?\", ne_ssl_clicert_encrypted(cc));\n    cert = ne_ssl_clicert_owner(cc);\n    ONN(\"client cert had no certificate\", cert == NULL);\n    CALL(check_dname(ne_ssl_cert_subject(cert),\n                     \"Neon Client Cert, Neon Hackers Ltd, \"\n                     \"Cambridge, Cambridgeshire, GB\",\n                     \"client cert subject\"));\n    CALL(check_dname(ne_ssl_cert_issuer(cert), CACERT_DNAME, \n                     \"client cert issuer\"));\n\n    cc2 = ne_ssl_clicert_copy(cc);\n    ONN(\"could not load unencrypted cert unclient.p12\", cc == NULL);\n    ONN(\"copied cert marked encrypted?\", ne_ssl_clicert_encrypted(cc));\n    cert = ne_ssl_clicert_owner(cc);\n    ONN(\"client cert had no certificate\", cert == NULL);\n    ONCMP(ne_ssl_clicert_name(cc), ne_ssl_clicert_name(cc2),\n          \"clicert\", \"duplicate cert name\");\n    ne_ssl_clicert_free(cc2);\n    ne_ssl_clicert_free(cc);\n\n    /* test for ccert without a friendly name, noclient.p12 */\n    cc = ne_ssl_clicert_read(\"noclient.p12\");\n    ONN(\"could not load noclient.p12\", cc == NULL);\n    name = ne_ssl_clicert_name(cc);\n    ONV(name != NULL, (\"noclient.p12 had friendly name `%s'\", name));\n    ne_ssl_clicert_free(cc);\n\n    /* test for ccert with a bundled CA. */\n    cc = ne_ssl_clicert_read(\"clientca.p12\");\n    ONN(\"could not load clientca.p12\", cc == NULL);\n    ONN(\"encrypted cert marked unencrypted?\", !ne_ssl_clicert_encrypted(cc));\n    ONN(\"could not decrypt clientca.p12\", \n        ne_ssl_clicert_decrypt(cc, P12_PASSPHRASE));\n    ne_ssl_clicert_free(cc);\n\n    /* test for ccert without a private key, nkclient.p12 */\n    cc = ne_ssl_clicert_read(\"nkclient.p12\");\n    ONN(\"did not fail to load clicert without pkey\", cc != NULL);\n    \n    /* test for ccert without a cert, ncclient.p12 */\n    cc = ne_ssl_clicert_read(\"ncclient.p12\");\n    ONN(\"did not fail to load clicert without cert\", cc != NULL);\n\n    /* tests for loading bogus files. */\n    cc = ne_ssl_clicert_read(\"Makefile\");\n    ONN(\"loaded Makefile as client cert!?\", cc != NULL);\n\n    /* test for loading nonexistent file. */\n    cc = ne_ssl_clicert_read(\"nosuch.pem\");\n    ONN(\"loaded nonexistent file as client cert!?\", cc != NULL);\n\n    return OK;\n}\n\nstatic int clicert_import(void)\n{\n    ne_ssl_client_cert *cc;\n    ne_buffer *buf = ne_buffer_create();\n\n    CALL(file_to_buffer(\"client.p12\", buf));\n\n    cc = ne_ssl_clicert_import((unsigned char *)buf->data, ne_buffer_size(buf));\n    ONN(\"could not import client cert from buffer\", cc == NULL);\n    \n    ONN(\"failed to decrypt\", ne_ssl_clicert_decrypt(cc, P12_PASSPHRASE));\n    ne_ssl_clicert_free(cc);\n    ne_buffer_destroy(buf);\n\n    return OK;\n}\n\n/* Test that 'cert', which is signed by CA_CERT, is accepted\n * unconditionally. */\nstatic int accept_signed_cert_for_hostname(char *cert, const char *hostname)\n{\n    struct ssl_server_args args = {cert, 0};\n\n    /* no verify callback needed. */\n    return make_ssl_request(&args, CA_CERT, hostname, NULL, NULL);\n}\n\n\nstatic int accept_signed_cert(char *cert)\n{\n    return accept_signed_cert_for_hostname(cert, \"localhost\");\n}\n\nstatic int simple(void)\n{\n    return accept_signed_cert(SERVER_CERT);\n}\n\n/* Test read-til-EOF behaviour with SSL. */\nstatic int simple_eof(void)\n{\n    struct ssl_server_args args = {SERVER_CERT, 0};\n\n    args.response = \"HTTP/1.0 200 OK\\r\\n\"\n        \"Connection: close\\r\\n\"\n        \"\\r\\n\"\n        \"This is a response body, like it or not.\";\n\n    return make_ssl_request(&args, CA_CERT, NULL, NULL, NULL);\n}\n\nstatic int intermediary(void)\n{\n    struct ssl_server_args args = {CA2_SERVER_CERT, 0};\n\n    return make_ssl_request(&args, CA_CERT, NULL, NULL, NULL);\n}\n\nstatic int empty_truncated_eof(void)\n{\n    struct ssl_server_args args = {0};\n\n    args.cert = SERVER_CERT;\n    args.response = \"HTTP/1.0 200 OK\\r\\n\" \"\\r\\n\";\n    \n    return make_ssl_request(&args, CA_CERT, NULL, NULL, NULL);\n}\n\n/* Server function which just sends a string then EOF. */\nstatic int just_serve_string(ne_socket *sock, void *userdata)\n{\n    const char *str = userdata;\n    server_send(sock, str, strlen(str));\n    return 0;\n}\n\n/* test for the SSL negotiation failing. */\nstatic int fail_not_ssl(void)\n{\n    ne_session *sess;\n    int ret;\n    \n    CALL(make_ssl_session(&sess, NULL, just_serve_string, \"Hello, world.\\n\"));\n    ret = any_request(sess, \"/bar\");\n    ONN(\"request did not fail\", ret != NE_ERROR);\n\n    return destroy_and_wait(sess);\n}\n\nstatic int wildcard_match(void)\n{\n    struct ssl_server_args args = {\"wildcard.cert\", 0};\n\n    return make_ssl_request(&args, CA_CERT, \"bar.example.com\", NULL, NULL);\n}\n\nstatic int wildcard_match_altname(void)\n{\n    struct ssl_server_args args = {\"altname9.cert\", 0};\n\n    return make_ssl_request(&args, CA_CERT, \"foo.example.com\", NULL, NULL);\n}\n\n/* Check that hostname comparisons are not cases-sensitive. */\nstatic int caseless_match(void)\n{\n    return accept_signed_cert(\"caseless.cert\");\n}\n\n/* Test that the subjectAltName extension has precedence over the\n * commonName attribute */\nstatic int subject_altname(void)\n{\n    return accept_signed_cert(\"altname1.cert\");\n}\n\n/* tests for multiple altNames. */\nstatic int two_subject_altname(void)\n{\n    return accept_signed_cert(\"altname2.cert\");\n}\n\nstatic int two_subject_altname2(void)\n{\n    return accept_signed_cert(\"altname3.cert\");\n}\n\n/* Test that a subject altname with *only* an eMail entry is\n * ignored, and the commonName is used instead. */\nstatic int notdns_altname(void)\n{\n    return accept_signed_cert(\"altname4.cert\");\n}\n\nstatic int ipaddr_altname(void)\n{\n    return accept_signed_cert_for_hostname(\"altname5.cert\", \"127.0.0.1\");\n}\n\n/* test that the *most specific* commonName attribute is used. */\nstatic int multi_commonName(void)\n{\n    return accept_signed_cert(\"twocn.cert\");\n}\n\n/* regression test for neon <= 0.23.4 where if commonName was the first\n * RDN in the subject DN, it was ignored. */\nstatic int commonName_first(void)\n{\n    return accept_signed_cert(\"cnfirst.cert\");\n}\n\nstatic int check_dname(const ne_ssl_dname *dn, const char *expected,\n                       const char *which)\n{\n    char *dname;\n\n    ONV(dn == NULL, (\"certificate %s dname was NULL\", which));\n    \n    dname = ne_ssl_readable_dname(dn);\n\n    NE_DEBUG(NE_DBG_SSL, \"Got dname `%s', expecting `%s'\\n\", dname, expected);\n\n    ONV(!dname || strcmp(dname, expected),\n        (\"certificate %s dname was `%s' not `%s'\", which, dname, expected));\n\n    ne_free(dname);\n\n    return 0;\n}\n\n/* Check that the readable subject issuer dnames of 'cert' match\n * 'subject' and 'issuer' (if non-NULL). */\nstatic int check_cert_dnames(const ne_ssl_certificate *cert,\n                             const char *subject, const char *issuer)\n{\n    ONN(\"no server certificate presented\", cert == NULL);\n    CALL(check_dname(ne_ssl_cert_subject(cert), subject, \"subject\"));\n    return issuer ? check_dname(ne_ssl_cert_issuer(cert), issuer, \"issuer\") : OK;\n}\n\n/* Verify callback which checks that the certificate presented has the\n * predetermined subject and issuer DN (as per makekeys.sh). */\nstatic int check_cert(void *userdata, int fs, const ne_ssl_certificate *cert)\n{\n    int *ret = userdata;\n\n    if (check_cert_dnames(cert, SERVER_DNAME, CACERT_DNAME) == FAIL)\n        *ret = -1;\n    else\n        *ret = 1;\n\n    return 0;\n}\n\n/* Check that certificate attributes are passed correctly. */\nstatic int parse_cert(void)\n{\n    struct ssl_server_args args = {SERVER_CERT, 0};\n    int ret = 0;\n\n    /* don't give a CA cert; should force the verify callback to be\n     * used. */\n    CALL(make_ssl_request(&args, NULL, NULL, check_cert, &ret));\n\n    ONN(\"cert verification never called\", ret == 0);\n\n    if (ret == -1)\n\treturn FAIL;\n\n    return OK;\n}\n\n#define WRONGCN_DNAME \"Bad Hostname Department, Neon Hackers Ltd, \" \\\n    \"Cambridge, Cambridgeshire, GB\"\n\n/* Check the certificate chain presented against known dnames. */\nstatic int check_chain(void *userdata, int fs, const ne_ssl_certificate *cert)\n{\n    int *ret = userdata;\n\n    if (check_cert_dnames(cert, WRONGCN_DNAME, CACERT_DNAME) == FAIL) {\n        *ret = -1;\n        return 0;\n    }\n    \n    cert = ne_ssl_cert_signedby(cert);\n    if (cert == NULL) {\n        t_context(\"no CA cert in chain\");\n        *ret = -1;\n        return 0;\n    }\n    \n    if (check_cert_dnames(cert, CACERT_DNAME, CACERT_DNAME) == FAIL) {\n        *ret = -1;\n        return 0;\n    }\n    \n    *ret = 1;\n    return 0;\n}\n\n/* Check that certificate attributes are passed correctly. */\nstatic int parse_chain(void)\n{\n    int ret = 0;\n    struct ssl_server_args args = {\"wrongcn.cert\", 0};\n\n    args.ca_list = CA_CERT;\n\n    /* The cert is signed by the CA but has a CN mismatch, so will\n     * force the verification callback to be invoked. */\n    CALL(make_ssl_request(&args, CA_CERT, NULL, check_chain, &ret));\n\n    ONN(\"cert verification never called\", ret == 0);\n\n    if (ret == -1)\n\treturn FAIL;\n\n    return OK;\n}\n\n\nstatic int count_vfy(void *userdata, int fs, const ne_ssl_certificate *c)\n{\n    int *count = userdata;\n    (*count)++;\n    return 0;\n}\n\nstatic int no_verify(void)\n{\n    int count = 0;\n    struct ssl_server_args args = {SERVER_CERT, 0};\n\n    CALL(make_ssl_request(&args, CA_CERT, NULL, count_vfy, &count));\n\n    ONN(\"verify callback called unnecessarily\", count != 0);\n\n    return OK;\n}\n\n/* Checks that the verify callback is only called on the first\n * connection to the SSL server, and not on subsequent connections. */\nstatic int cache_verify(void)\n{\n    ne_session *sess;\n    int count = 0;\n    struct ssl_server_args args = {SERVER_CERT, 0};\n\n    CALL(multi_ssl_session(2, &sess, &args));\n\n    ne_ssl_set_verify(sess, count_vfy, &count);\n\n    ONREQ(any_request(sess, \"/foo-alpha\"));\n    ONREQ(any_request(sess, \"/foo-beta\"));\n\n    ONV(count != 1,\n\t(\"verify callback result not cached: called %d times\", count));\n\n    ne_session_destroy(sess);\n\n    return OK;\n}\n\n/* Copy failures into *userdata, and fail verification. */\nstatic int get_failures(void *userdata, int fs, const ne_ssl_certificate *c)\n{\n    int *out = userdata;\n    *out = fs;\n    NE_DEBUG(NE_DBG_SSL, \"test: fail_ssl_request verify callback - %d\\n\", fs);\n    return -1;\n}\n\n/* Helper function for expected-to-fail SSL tests.\n *\n * An SSL server is spawned using 'cert' and 'key' as the key pair.\n * The client will trust CA cert 'cacert', and use 'host' as the server\n * name.  If realhost is non-NULL, this address will be used to connect\n * to in favour of host; the server is otherwise identified as 'host'.\n * 'msg' must be a substring of the error string.\n * 'failures' must equal the failure bitmask passed to the verify\n * callback in the client.\n * If none of the expected conditions is met, 'errstr' will be\n * used in the test failure context.\n */\nstatic int fail_ssl_request_with_error2(char *cert, char *key, char *cacert, \n                                        const char *host, const char *realhost,\n                                        const char *msg, int failures,\n                                        const char *errstr)\n{\n    ne_session *sess;\n    int gotf = 0, ret;\n    struct ssl_server_args args = {0};\n    ne_sock_addr *addr = NULL;\n    const ne_inet_addr **list = NULL;\n\n    args.cert = cert;\n    args.key = key;\n    args.fail_silently = 1;\n    \n    CALL(fakeproxied_session_server(&sess, \"https\", host, 7777, ssl_server, &args));\n\n    if (cacert) {\n        CALL(load_and_trust_cert(sess, cacert));\n    }\n\n    ne_ssl_set_verify(sess, get_failures, &gotf);\n\n    ret = any_request(sess, \"/expect-to-fail\");\n\n    NE_DEBUG(NE_DBG_SSL, \"test: fail_ssl_request - request code %d, error: %s\\n\",\n             ret, ne_get_error(sess));\n\n    ONV(gotf == 0,\n\t(\"no error in verification callback; request rv %d error string: %s\",\n\t ret, ne_get_error(sess)));\n\n    ONV(gotf & ~NE_SSL_FAILMASK,\n\t(\"verification flags %x outside mask %x\", gotf, NE_SSL_FAILMASK));\n\n    /* check the failure flags were as expected. */\n    ONV(failures != gotf,\n\t(\"verification flags were %d not %d\", gotf, failures));\n\n    /* and check that the request was failed too. */\n    ONV(ret == NE_OK, (\"%s\", msg));\n\n    ONV(errstr && strstr(ne_get_error(sess), errstr) == NULL,\n        (\"unexpected failure message '%s', wanted '%s'\",\n         ne_get_error(sess), errstr));\n        \n    ne_session_destroy(sess);\n    if (addr) ne_addr_destroy(addr);\n    if (list) ne_free(list);\n\n    return OK;\n}\n\n/* Helper function: run a request using the given self-signed server\n * certificate, and expect the request to fail with the given\n * verification failure flags. */\nstatic int fail_ssl_request_with_error(char *cert, char *cacert, const char *host,\n                                       const char *msg, int failures,\n                                       const char *errstr)\n{\n    return fail_ssl_request_with_error2(cert, NULL, cacert, host, NULL,\n                                        msg, failures, errstr);\n}\n\n\n/* Helper function: run a request using the given self-signed server\n * certificate, and expect the request to fail with the given\n * verification failure flags. */\nstatic int fail_ssl_request(char *cert, char *cacert, const char *host,\n\t\t\t    const char *msg, int failures)\n{\n    return fail_ssl_request_with_error(cert, cacert, host, msg, failures,\n                                       NULL);\n}        \n\n/* Note that the certs used for fail_* are mostly self-signed, so the\n * cert is passed as CA cert and server cert to fail_ssl_request. */\n\n/* Check that a certificate with the incorrect commonName attribute is\n * flagged as such. */\nstatic int fail_wrongCN(void)\n{\n    return fail_ssl_request_with_error(\"wrongcn.cert\", \"ca/cert.pem\", \"localhost\",\n                                       \"certificate with incorrect CN was accepted\",\n                                       NE_SSL_IDMISMATCH,\n                                       \"certificate issued for a different hostname\");\n                            \n}\n\n#define SRCDIR(s) ne_concat(srcdir, \"/\" s, NULL)\n\n#if 0\nstatic int fail_nul_cn(void)\n{\n    char *key = SRCDIR(\"nulsrv.key\"), *ca = SRCDIR(\"nulca.pem\");\n    CALL(fail_ssl_request_with_error2(nul_cn_fn, key, ca,\n                                      \"www.bank.com\", \"localhost\",\n                                      \"certificate with incorrect CN was accepted\",\n                                      NE_SSL_IDMISMATCH|NE_SSL_EXPIRED|NE_SSL_BADCHAIN,\n                                      \"certificate issued for a different hostname\"));\n    ne_free(key);\n    ne_free(ca);\n    return OK;\n}\n\nstatic int fail_nul_san(void)\n{\n    char *cert = SRCDIR(\"nulsan.pem\"), *key = SRCDIR(\"nulsrv.key\"),\n        *ca = SRCDIR(\"nulca.pem\");\n    CALL(fail_ssl_request_with_error2(cert, key, ca, \n                                      \"www.bank.com\", \"localhost\",\n                                      \"certificate with incorrect CN was accepted\",\n                                      NE_SSL_IDMISMATCH|NE_SSL_EXPIRED|NE_SSL_BADCHAIN,\n                                      \"certificate issued for a different hostname\"));\n    ne_free(cert);\n    ne_free(key);\n    ne_free(ca);\n    return OK;\n}\n#endif\n\n/* Check that an expired certificate is flagged as such. */\nstatic int fail_expired(void)\n{\n    return fail_ssl_request_with_error(\"expired.cert\", CA_CERT,  \"localhost\",\n                                       \"expired certificate was accepted\", \n                                       NE_SSL_EXPIRED,\n                                       \"certificate has expired\");\n}\n\nstatic int fail_notvalid(void)\n{\n    return fail_ssl_request_with_error(\"notyet.cert\", CA_CERT,  \"localhost\",\n                                       \"not yet valid certificate was accepted\",\n                                       NE_SSL_NOTYETVALID,\n                                       \"certificate is not yet valid\");\n}\n\n/* Check that a server cert with a random issuer and self-signed cert\n * fail with UNTRUSTED. */\nstatic int fail_untrusted_ca(void)\n{\n    return fail_ssl_request_with_error(\"server.cert\", NULL, \"localhost\",\n                                       \"untrusted CA.\", NE_SSL_UNTRUSTED,\n                                       \"issuer is not trusted\");\n}\n\nstatic int fail_self_signed(void)\n{\n    return fail_ssl_request(\"ssigned.pem\", NULL,  \"localhost\",\n                            \"self-signed cert\", NE_SSL_UNTRUSTED);\n}\n\n/* Test for failure when a server cert is presented which has no\n * commonName (and no alt names either). */\nstatic int fail_missing_CN(void)\n{\n    struct ssl_server_args args = {0};\n    ne_session *sess;\n    int ret;\n\n    args.cert = \"missingcn.cert\";\n\n    CALL(make_ssl_session(&sess, \"localhost\", ssl_server, &args));\n\n    ret = any_request(sess, \"/fail-missing-cn\");\n    ONN(\"request did not fail\", ret != NE_ERROR);\n\n    ONV(strstr(ne_get_error(sess), \"missing commonName attribute\") == NULL,\n        (\"error string unexpected: %s\", ne_get_error(sess)));\n\n    return destroy_and_wait(sess);\n}\n\n/* test for a bad ipAddress altname */\nstatic int fail_bad_ipaltname(void)\n{\n    return fail_ssl_request(\"altname6.cert\", CA_CERT, \"127.0.0.1\",\n                            \"bad IP altname cert\", NE_SSL_IDMISMATCH);\n}\n\n/* test for a ipAddress which matched against the hostname as per neon\n * 0.24 behaviour. */\nstatic int fail_host_ipaltname(void)\n{\n    return fail_ssl_request(\"altname5.cert\", CA_CERT, \"localhost\",\n                            \"bad IP altname cert\", NE_SSL_IDMISMATCH);\n}\n\nstatic int fail_wildcard(void)\n{\n    return fail_ssl_request(\"altname9.cert\", CA_CERT, \"localhost\",\n                            \"subjaltname not honored\", NE_SSL_IDMISMATCH);\n}\n\nstatic int fail_wildcard_ip(void)\n{\n    return fail_ssl_request(\"wildip.cert\", CA_CERT, \"127.0.0.1\",\n                            \"wildcard IP\", NE_SSL_IDMISMATCH);\n}\n\nstatic int fail_ca_expired(void)\n{\n    return fail_ssl_request_with_error(\"ca1server.cert\", \"ca1/cert.pem\", \n                                       \"localhost\", \"issuer ca expired\", \n                                       NE_SSL_BADCHAIN,\n                                       \"bad certificate chain\");\n}\n\nstatic int fail_ca_notyetvalid(void)\n{\n    return fail_ssl_request(\"ca3server.cert\", \"ca3/cert.pem\", \"localhost\",\n                            \"issuer ca not yet valid\", NE_SSL_BADCHAIN);\n}\n\n/* Test that the SSL session is cached across connections. */\nstatic int session_cache(void)\n{\n    struct ssl_server_args args = {0};\n    ne_session *sess;\n\n    args.cert = SERVER_CERT;\n    args.cache = 1;\n\n    CALL(multi_ssl_session(2, &sess, &args));\n\n    /* This currently fails under OpenSSL with TLSv1.3. */\n    ne_ssl_set_protovers(sess, NE_SSL_PROTO_UNSPEC,\n                         NE_SSL_PROTO_TLS_1_2);\n\n    ne_ssl_trust_cert(sess, def_ca_cert);\n\n    ONREQ(any_request(sess, \"/req1\"));\n    ONREQ(any_request(sess, \"/req2\"));\n\n    return destroy_and_wait(sess);\n}\n\n/* Callback for client_cert_provider; takes a c. cert as userdata and\n * registers it. */\nstatic void ccert_provider(void *userdata, ne_session *sess,\n                           const ne_ssl_dname *const *dns, int dncount)\n{\n    const ne_ssl_client_cert *cc = userdata;\n    ne_ssl_set_clicert(sess, cc);\n}\n\n/* Test that the on-demand client cert provider callback is used. */\nstatic int client_cert_provided(void)\n{\n    ne_session *sess;\n    ne_ssl_client_cert *cc;\n    struct ssl_server_args args = {SERVER_CERT, NULL};\n\n    args.require_cc = 1;\n\n    CALL(make_ssl_session(&sess, \"localhost\", ssl_server, &args));\n    CALL(load_and_trust_cert(sess, CA_CERT));\n\n    cc = ne_ssl_clicert_read(\"client.p12\");\n    ONN(\"could not load client.p12\", cc == NULL);\n    ONN(\"could not decrypt client.p12\", \n        ne_ssl_clicert_decrypt(cc, P12_PASSPHRASE));\n    ne_ssl_provide_clicert(sess, ccert_provider, cc);\n\n    CALL(any_request(sess, \"/withcert\"));\n\n    ne_ssl_clicert_free(cc);\n    return destroy_and_wait(sess);\n}\n\n#define DN_COUNT 5\n\nstatic void cc_check_dnames(void *userdata, ne_session *sess,\n                            const ne_ssl_dname *const *dns, int dncount)\n{\n    int n, *ret = userdata;\n    static const char *expected[DN_COUNT] = {\n        CACERT_DNAME,\n        \"First Random CA, CAs Ltd., Lincoln, Lincolnshire, GB\",\n        \"Second Random CA, CAs Ltd., Falmouth, Cornwall, GB\",\n        \"Third Random CA, CAs Ltd., Ipswich, Suffolk, GB\",\n        \"Fourth Random CA, CAs Ltd., Norwich, Norfolk, GB\"\n    };\n\n    ne_ssl_set_clicert(sess, def_cli_cert);\n\n    if (dncount != DN_COUNT) {\n        t_context(\"dname count was %d not %d\", dncount, \n                  DN_COUNT);\n        *ret = -1;\n        return;\n    }\n    \n    for (n = 0; n < DN_COUNT; n++) {\n        char which[5];\n\n        sprintf(which, \"%d\", n);\n\n        if (check_dname(dns[n], expected[n], which) == FAIL) {\n            *ret = -1;\n            return;\n        }\n    }\n\n    *ret = 1;\n}\n\n/* Test for the list of acceptable dnames sent to the client. */\nstatic int cc_provided_dnames(void)\n{\n    int check = 0;\n    ne_session *sess;\n    struct ssl_server_args args = {SERVER_CERT, NULL};\n\n    args.require_cc = 1;\n    args.ca_list = \"calist.pem\";\n\n    PRECOND(def_cli_cert);\n\n    CALL(make_ssl_session(&sess, \"localhost\", ssl_server, &args));\n\n    ne_ssl_provide_clicert(sess, cc_check_dnames, &check);\n    CALL(load_and_trust_cert(sess, CA_CERT));\n    CALL(any_request(sess, \"/foo\"));\n\n    CALL(destroy_and_wait(sess));\n\n    ONN(\"provider function not called\", check == 0);\n\n    return (check == -1) ? FAIL : OK;\n}\n\n/* Tests use of a client certificate. */\nstatic int client_cert_pkcs12(void)\n{\n    ne_session *sess;\n    struct ssl_server_args args = {SERVER_CERT, NULL};\n\n    args.require_cc = 1;\n\n    PRECOND(def_cli_cert);\n\n    CALL(make_ssl_session(&sess, \"localhost\", ssl_server, &args));\n\n    ne_ssl_set_clicert(sess, def_cli_cert);\n    CALL(load_and_trust_cert(sess, CA_CERT));\n    CALL(any_request(sess, \"/foo\"));\n\n    return destroy_and_wait(sess);\n}\n\n/* Test use of a PKCS#12 cert with an embedded CA cert - fails with <=\n * 0.28.3 in GnuTLS build. */\nstatic int client_cert_ca(void)\n{\n    ne_session *sess;\n    struct ssl_server_args args = {SERVER_CERT, NULL};\n    ne_ssl_client_cert *cc;\n\n    args.require_cc = 1;\n\n    cc = ne_ssl_clicert_read(\"clientca.p12\");\n    ONN(\"could not load clientca.p12\", cc == NULL);\n    ONN(\"encrypted cert marked unencrypted?\", !ne_ssl_clicert_encrypted(cc));\n    ONN(\"could not decrypt clientca.p12\", \n        ne_ssl_clicert_decrypt(cc, P12_PASSPHRASE));\n\n    CALL(make_ssl_session(&sess, \"localhost\", ssl_server, &args));\n    ne_ssl_set_clicert(sess, cc);\n    CALL(load_and_trust_cert(sess, CA_CERT));\n\n    CALL(any_request(sess, \"/foo\"));\n\n    ne_ssl_clicert_free(cc);\n    return destroy_and_wait(sess);\n}\n\n/* Tests use of an unencrypted client certificate. */\nstatic int ccert_unencrypted(void)\n{\n    ne_session *sess;\n    ne_ssl_client_cert *ccert;\n    struct ssl_server_args args = {SERVER_CERT, NULL};\n\n    args.require_cc = 1;\n\n    ccert = ne_ssl_clicert_read(\"unclient.p12\");\n    ONN(\"could not load unclient.p12\", ccert == NULL);\n    ONN(\"unclient.p12 was encrypted\", ne_ssl_clicert_encrypted(ccert));\n\n    CALL(make_ssl_session(&sess, \"localhost\", ssl_server, &args));\n\n    ne_ssl_set_clicert(sess, ccert);\n    CALL(load_and_trust_cert(sess, CA_CERT));\n    CALL(any_request(sess, \"/foo\"));\n\n    /* Calling twice to ensure there is no memory leaked. */\n    ne_ssl_set_clicert(sess, ccert);\n\n    ne_ssl_clicert_free(ccert);\n    return destroy_and_wait(sess);\n}\n\n#define NOCERT_MESSAGE \"client certificate was requested\"\n/* random SSL read may fail like this with TLSv1.3 */\n#define NOCERT_ALT \"certificate required\"\n\n/* GnuTLS fails to note the cc request in the error path for\n * TLSv1.3; for OpenSSL test with TLSv1.2 and 1.3. */\n#ifdef HAVE_GNUTLS\n#define NCC_MAX (1)\n#else\n#define NCC_MAX (2)\n#endif\n\n/* Tests for useful error message if a handshake fails where a client\n * cert was requested. */\nstatic int no_client_cert(void)\n{\n    unsigned i;\n\n    for (i = 0; i < NCC_MAX; i++) {\n        ne_session *sess;\n        struct ssl_server_args args = {SERVER_CERT, NULL};\n        int ret;\n\n        args.require_cc = 1;\n        args.fail_silently = 1;\n\n        CALL(make_ssl_session(&sess, NULL, ssl_server, &args));\n        ne_ssl_trust_cert(sess, def_ca_cert);\n\n        if (i == 0)\n            ne_ssl_set_protovers(sess, NE_SSL_PROTO_TLS_1_2, NE_SSL_PROTO_TLS_1_2);\n\n        ret = any_request(sess, i ? \"failme-tls12\" : \"/failme\");\n        ONV(ret != NE_ERROR,\n            (\"unexpected result %d: %s\", ret, ne_get_error(sess)));\n\n        ONV(strstr(ne_get_error(sess), NOCERT_MESSAGE) == NULL\n            && strstr(ne_get_error(sess), NOCERT_ALT) == NULL,\n            (\"error message was '%s', missing '%s'\",\n             ne_get_error(sess), NOCERT_MESSAGE));\n\n        CALL(destroy_and_wait(sess));\n    }\n\n    return OK;\n}\n\n/* non-zero if a server auth header was received */\nstatic int got_server_auth; \n\n/* Utility function which accepts the 'tunnel' header. */\nstatic void tunnel_header(char *value)\n{\n    got_server_auth = 1;\n}\n\n/* Server which acts as a proxy accepting a CONNECT request. */\nstatic int serve_tunnel(ne_socket *sock, void *ud)\n{\n    struct ssl_server_args *args = ud;\n\n    /* check for a server auth function */\n    want_header = \"Authorization\";\n    got_header = tunnel_header;\n    got_server_auth = 0;\n\n    /* give the plaintext tunnel reply, acting as the proxy */\n    CALL(discard_request(sock));\n\n    if (got_server_auth) {\n        SEND_STRING(sock, \"HTTP/1.1 500 Leaked Server Auth Creds\\r\\n\"\n                    \"Content-Length: 0\\r\\n\" \"Server: serve_tunnel\\r\\n\\r\\n\");\n        return 0;\n    } else {\n        SEND_STRING(sock, \"HTTP/1.1 200 OK\\r\\nServer: serve_tunnel\\r\\n\\r\\n\");\n        return ssl_server(sock, args);\n    }\n}\n\n/* neon versions <= 0.21.2 segfault here because ne_sock_close would\n * be called twice on the socket after the server cert verification\n * fails. */\nstatic int fail_tunnel(void)\n{\n    struct ssl_server_args args = {SERVER_CERT, NULL};\n    ne_session *sess;\n\n    CALL(proxied_session_server(&sess, \"https\", \"dontmatch.example.com\", 443,\n                                serve_tunnel, &args));\n    CALL(load_and_trust_cert(sess, CA_CERT));\n    ONN(\"server cert verification didn't fail\",\n        any_request(sess, \"/tunnelled\") != NE_ERROR);\n    \n    return destroy_and_wait(sess);\n}\n\nstatic int proxy_tunnel(void)\n{\n    struct ssl_server_args args = {SERVER_CERT, NULL};\n    ne_session *sess;\n\n    CALL(proxied_session_server(&sess, \"https\", \"localhost\", 443,\n                                serve_tunnel, &args));\n    CALL(load_and_trust_cert(sess, CA_CERT));\n    CALL(any_request(sess, \"/tunnelled\"));\n    return destroy_and_wait(sess);\n}\n\nstruct tunnel_args {\n    int iteration;\n    const char *first_response; /* first CONNECT response. */\n    const char *second_response; /* second CONNECT response. */\n    struct ssl_server_args *args;\n};\n\n/* Server which acts as a proxy accepting a CONNECT request. */\nstatic int serve_auth_tunnel(ne_socket *sock, void *ud)\n{\n    struct tunnel_args *args = ud;\n\n    /* check for a server auth function */\n    want_header = \"Authorization\";\n    got_header = tunnel_header;\n    got_server_auth = 0;\n\n    CALL(discard_request(sock));\n\n    if (got_server_auth) {\n        SEND_STRING(sock, \"HTTP/1.1 500 Leaked Server Auth Creds\\r\\n\"\n                    \"Content-Length: 0\\r\\n\" \"Server: serve_tunnel\\r\\n\\r\\n\");\n        return 0;\n    }\n    \n    if (args->iteration++ == 0) {\n        /* give the plaintext tunnel reply, acting as the proxy */\n\n        SEND_STRING(sock, args->first_response);\n\n        return OK;\n    }\n\n    SEND_STRING(sock, args->second_response);\n\n    return ssl_server(sock, args->args);\n}\n\nstatic int apt_creds(void *userdata, const char *realm, int attempt,\n                     char *username, char *password)\n{\n    strcpy(username, \"foo\");\n    strcpy(password, \"bar\");\n    return attempt;\n}\n\n/* Test for using SSL over a CONNECT tunnel via a proxy server which\n * requires authentication.  Broke briefly between 0.23.x and\n * 0.24.0. */\nstatic int auth_proxy_tunnel(void)\n{\n    struct ssl_server_args args = {SERVER_CERT, NULL};\n    struct tunnel_args tunnel;\n    ne_session *sess;\n\n    tunnel.first_response =\n        \"HTTP/1.0 407 I WANT MORE BISCUITS\\r\\n\"\n        \"Server: auth_proxy_tunnel\\r\\n\"\n        \"Proxy-Authenticate: Basic realm=\\\"bigbluesea\\\"\\r\\n\"\n        \"Connection: close\\r\\n\" \"\\r\\n\";\n    tunnel.second_response = \"HTTP/1.1 200 OK\\r\\n\"\n        \"Server: auth_proxy_tunnel r2\\r\\n\\r\\n\";\n    tunnel.iteration = 0;\n    tunnel.args = &args;\n\n    CALL(proxied_multi_session_server(2, &sess, \"https\", \"localhost\", 443,\n                                      serve_auth_tunnel, &tunnel));\n    \n    ne_set_proxy_auth(sess, apt_creds, NULL);\n    ne_ssl_trust_cert(sess, def_ca_cert);\n    \n    CALL(any_2xx_request(sess, \"/foobar\"));\n\n    return destroy_and_wait(sess);\n}\n\n/* Regression test to check that server credentials aren't sent to the\n * proxy in a CONNECT request. */\nstatic int auth_tunnel_creds(void)\n{\n    struct ssl_server_args args = {SERVER_CERT, NULL};\n    struct tunnel_args tunnel;\n    ne_session *sess;\n\n    args.response = \"HTTP/1.1 401 I want a Shrubbery\\r\\n\"\n        \"WWW-Authenticate: Basic realm=\\\"bigredocean\\\"\\r\\n\"\n        \"Server: auth_tunnel_creds\\r\\n\" \"Content-Length: 0\\r\\n\" \"\\r\\n\"\n        \"\"\n        \"HTTP/1.1 200 OK\\r\\n\\r\\n\";\n\n    tunnel.second_response = \"HTTP/1.1 200 OK\\r\\n\\r\\n\";\n    tunnel.args = &args;\n    tunnel.iteration = 1;\n\n    CALL(proxied_multi_session_server(2, &sess, \"https\", \"localhost\", 443,\n                                      serve_auth_tunnel, &tunnel));\n    \n    ne_set_server_auth(sess, apt_creds, NULL);\n    ne_ssl_trust_cert(sess, def_ca_cert);\n    \n    CALL(any_2xx_request(sess, \"/foobar\"));\n    CALL(any_2xx_request(sess, \"/foobar\"));\n\n    return destroy_and_wait(sess);\n}\n\nstatic int auth_tunnel_fail(void)\n{\n    ne_session *sess;\n    int ret;\n\n    CALL(proxied_session_server(&sess, \"https\", \"localhost\", 7777,\n                                single_serve_string,\n                                \"HTTP/1.1 407 Nyaaaaah\\r\\n\"\n                                \"Proxy-Authenticate: GaBoogle\\r\\n\"\n                                \"Content-Length: 0\\r\\n\"\n                                \"\\r\\n\"\n                                \"HTTP/1.1 200 OK\\r\\n\"\n                                \"Content-Length: 0\\r\\n\"\n                                \"\\r\\n\"));\n\n    ne_set_proxy_auth(sess, apt_creds, NULL);\n\n    /* First request: should fail and the auth failure should\n     * propagate back to the session error string. */\n    ret = any_request(sess, \"/foo\");\n    ONV(ret != NE_PROXYAUTH, (\"bad error code for tunnel failure: %d\", ret));\n    ONV(strstr(ne_get_error(sess), \"GaBoogle\") == NULL,\n        (\"bad error string for tunnel failure: %s\", ne_get_error(sess)));\n\n    /* Second request must fail to connect, the connection should have\n     * been closed. */\n    ret = any_request(sess, \"/bar\");\n    ONV(ret != NE_CONNECT,\n        (\"second attempt should fail to connect, got: %d\", ret));\n\n    return destroy_and_wait(sess);\n}\n\n/* compare against known digest of notvalid.pem.  Via:\n *   $ openssl x509 -fingerprint -sha1 -noout -in notvalid.pem */\n#define THE_DIGEST \"cf:5c:95:93:76:c6:3c:01:8b:62:\" \\\n                   \"b1:6f:f7:7f:42:32:ac:e6:69:1b\"\n\nstatic int cert_fingerprint(void)\n{\n    char *fn = ne_concat(srcdir, \"/notvalid.pem\", NULL);\n    ne_ssl_certificate *cert = ne_ssl_cert_read(fn);\n    char digest[60];\n    \n    ne_free(fn);\n\n    ONN(\"could not load notvalid.pem\", cert == NULL);\n\n    ONN(\"failed to digest\", ne_ssl_cert_digest(cert, digest));\n    ne_ssl_cert_free(cert);\n\n    ONV(strcmp(digest, THE_DIGEST),\n        (\"digest was %s not %s\", digest, THE_DIGEST));\n\n    return OK;\n}\n\nstatic int cert_hdigests(void)\n{\n    static const struct {\n        unsigned int flags;\n        const char *digest;\n    } ts[] = {\n        { NE_HASH_MD5|NE_HASH_COLON, \"76:26:eb:db:09:e8:53:5c:79:61:0c:30:3d:77:ed:65\" },\n        { NE_HASH_MD5, \"7626ebdb09e8535c79610c303d77ed65\" },\n        { NE_HASH_SHA256, \"ea4a4f4f08a91a83e841e772171a2befa3f6e576b5cd9f5cd6d12e9683fe89b3\" },\n        { NE_HASH_SHA512, \"35373c533f4000ee9b6173a45eedae732f6c953dcf76f5fba5ffb7be380de559893d0679e94051950be2a5917fa7922fbf50ef10222d5be4eea53ba948cf7703\" },\n        { 0, NULL }\n    };\n    unsigned int n, passed = 0;\n    char *fn = ne_concat(srcdir, \"/notvalid.pem\", NULL);\n    ne_ssl_certificate *cert = ne_ssl_cert_read(fn);\n\n    ONN(\"could not load notvalid.pem\", cert == NULL);\n\n    for (n = 0; ts[n].flags; n++) {\n        char *dig = ne_ssl_cert_hdigest(cert, ts[n].flags);\n\n        /* Can reasonably for almost any hash (either too modern or\n         * too old), so what can you do? */\n        if (dig == NULL) {\n            t_warning(\"failed to htdigest with flags %u\", ts[n].flags);\n            continue;\n        }\n\n        NE_DEBUG(NE_DBG_SSL, \"ssl: hDigest %u got %s, expected %s\\n\",\n                 ts[n].flags, dig, ts[n].digest);\n\n        ONV(strcmp(dig, ts[n].digest),\n            (\"digest was %s not %s\", dig, ts[n].digest));\n\n        passed++;\n        ne_free(dig);\n    }\n\n    ONN(\"no algorithms supported for ne_ssl_cert_hdigest\", passed == 0);\n\n    ne_ssl_cert_free(cert);\n    ne_free(fn);\n\n    return OK;\n}\n\n/* verify that identity of certificate in filename 'fname' is 'identity' */\nstatic int check_identity(const char *fname, const char *identity)\n{\n    ne_ssl_certificate *cert = ne_ssl_cert_read(fname);\n    const char *id;\n\n    ONV(cert == NULL, (\"could not read cert `%s'\", fname));\n\n    id = ne_ssl_cert_identity(cert);\n\n    if (identity) {\n        ONV(id == NULL, (\"certificate `%s' had no identity\", fname));\n        ONV(strcmp(id, identity), \n            (\"certificate `%s' had identity `%s' not `%s'\", fname, \n             id, identity));\n    } else {\n        ONV(id != NULL, (\"certificate `%s' had identity `%s' (expected none)\",\n                         fname, id));\n    }            \n    \n    ne_ssl_cert_free(cert);\n    return OK;\n}\n\n/* check certificate identities. */\nstatic int cert_identities(void)\n{\n    static const struct {\n        const char *fname, *identity;\n    } certs[] = {\n        { \"ssigned.pem\", \"localhost\" },\n        { \"twocn.cert\", \"localhost\" },\n        { \"altname1.cert\", \"localhost\" },\n        { \"altname2.cert\", \"nohost.example.com\" },\n        { \"altname4.cert\", \"localhost\" },\n        { \"ca4.pem\", \"fourth.example.com\" },\n        { NULL, NULL }\n    };\n    int n;\n\n    for (n = 0; certs[n].fname != NULL; n++)\n        CALL(check_identity(certs[n].fname, certs[n].identity));\n\n    return OK;\n}\n\nstatic int nulcn_identity(void)\n{\n    ne_ssl_certificate *cert = ne_ssl_cert_read(nul_cn_fn);\n    const char *id;\n\n    ONN(\"could not read nulcn.pem\", cert == NULL);\n\n    id = ne_ssl_cert_identity(cert);\n\n    ONN(\"embedded NUL byte not quoted\",\n        id != NULL && strcmp(id, \"www.bank.com\") == 0);\n    \n    ne_ssl_cert_free(cert);\n    return OK;\n}\n\nstatic int check_validity(const char *fname,\n                          const char *from, const char *until)\n{\n    char actfrom[NE_SSL_VDATELEN], actuntil[NE_SSL_VDATELEN];\n    ne_ssl_certificate *cert;\n\n    cert = ne_ssl_cert_read(fname);\n    ONV(cert == NULL, (\"could not load cert `%s'\", fname));\n\n    /* cover all calling combos for nice coverage analysis */\n    ne_ssl_cert_validity(cert, NULL, NULL);\n    ne_ssl_cert_validity(cert, actfrom, NULL);\n    ne_ssl_cert_validity(cert, NULL, actuntil);\n    ne_ssl_cert_validity(cert, actfrom, actuntil);\n\n    ONV(strcmp(actfrom, from), \n        (\"%s: start time was `%s' not `%s'\", fname, actfrom, from));\n\n    ONV(strcmp(actuntil, until), \n        (\"%s: end time was `%s' not `%s'\", fname, actuntil, until));\n\n    ne_ssl_cert_free(cert);\n    return OK;\n}\n\n/* ceritificate validity times. */\nstatic int cert_validity(void)\n{\n    char *cert = ne_concat(srcdir, \"/expired.pem\", NULL);\n    CALL(check_validity(cert, \n                        \"Mon, 21 Jan 2002 20:39:04 GMT\", \"Thu, 31 Jan 2002 20:39:04 GMT\"));\n    ne_free(cert);\n    cert = ne_concat(srcdir, \"/notvalid.pem\", NULL);\n    CALL(check_validity(cert, \n                        \"Wed, 27 Dec 2023 20:40:29 GMT\", \"Thu, 28 Dec 2023 20:40:29 GMT\"));\n    ne_free(cert);\n    return OK;\n}\n\n/* dname comparisons. */\nstatic int dname_compare(void)\n{\n    ne_ssl_certificate *ssigned;\n    const ne_ssl_dname *dn1, *dn2;\n    \n    dn1 = ne_ssl_cert_subject(def_server_cert);\n    dn2 = ne_ssl_cert_subject(def_server_cert);\n    ONN(\"identical subject names not equal\", ne_ssl_dname_cmp(dn1, dn2) != 0);\n\n    dn2 = ne_ssl_cert_issuer(def_server_cert);\n    ONN(\"issuer and subject names equal for signed cert\",\n        ne_ssl_dname_cmp(dn1, dn2) == 0);\n    \n    dn1 = ne_ssl_cert_subject(def_ca_cert);\n    ONN(\"issuer of signed cert not equal to subject of CA cert\",\n        ne_ssl_dname_cmp(dn1, dn2) != 0);\n\n    ssigned = ne_ssl_cert_read(\"ssigned.pem\");\n    ONN(\"could not load ssigned.pem\", ssigned == NULL);\n\n    dn1 = ne_ssl_cert_subject(ssigned);\n    dn2 = ne_ssl_cert_issuer(ssigned);\n    ONN(\"issuer and subject names not equal for self-signed cert\",\n        ne_ssl_dname_cmp(dn1, dn2));\n    ne_ssl_cert_free(ssigned);\n\n    return OK;\n}\n\n/* The dname with the UTF-8 encoding of the Unicode string: \n * \"H<LATIN SMALL LETTER E WITH GRAVE>llo World\". */\n#define I18N_DNAME \"H\\xc3\\xa8llo World, Neon Hackers Ltd, Cambridge, Cambridgeshire, GB\"\n\n/* N.B. t61subj.cert encodes an ISO-8859-1 string in a T61String\n * field, which is strictly wrong but the common usage. */\n\n/* tests for ne_ssl_readable_dname */\nstatic int dname_readable(void)\n{\n    struct {\n        const char *cert;\n        const char *subjdn, *issuerdn;\n    } ts[] = {\n        { \"justmail.cert\", \"blah@example.com\", NULL },\n        { \"t61subj.cert\", I18N_DNAME, NULL },\n        { \"bmpsubj.cert\", I18N_DNAME, NULL },\n        { \"utf8subj.cert\", I18N_DNAME, NULL },\n        { \"twoou.cert\", \"First OU Dept, Second OU Dept, Neon Hackers Ltd, \"\n          \"Cambridge, Cambridgeshire, GB\", NULL }\n    };\n    size_t n;\n\n    for (n = 0; n < sizeof(ts)/sizeof(ts[0]); n++) {\n        ne_ssl_certificate *cert = ne_ssl_cert_read(ts[n].cert);\n        ONV(cert == NULL, (\"could not load cert %s\", ts[n].cert));\n        CALL(check_cert_dnames(cert, ts[n].subjdn, ts[n].issuerdn));\n        ne_ssl_cert_free(cert);\n    }\n\n    return OK;\n}\n\n/* test cert comparisons */\nstatic int cert_compare(void)\n{\n    ne_ssl_certificate *c1, *c2;\n\n    c1 = ne_ssl_cert_read(\"server.cert\");\n    c2 = ne_ssl_cert_read(\"server.cert\");\n    ONN(\"identical certs don't compare equal\", ne_ssl_cert_cmp(c1, c2) != 0);\n    ONN(\"identical certs don't compare equal\", ne_ssl_cert_cmp(c2, c1) != 0);\n    ne_ssl_cert_free(c2);\n\n    c2 = ne_ssl_cert_read(\"ssigned.pem\");\n    ONN(\"different certs don't compare different\",\n        ne_ssl_cert_cmp(c1, c2) == 0);\n    ONN(\"different certs don't compare different\",\n        ne_ssl_cert_cmp(c2, c1) == 0);\n    ne_ssl_cert_free(c2);\n    ne_ssl_cert_free(c1);\n\n    return OK;\n}\n\n/* Extract raw base64 string from a PEM file */\nstatic int flatten_pem(const char *fname, char **out)\n{\n    FILE *fp = fopen(fname, \"r\");\n    char buf[80];\n    size_t outlen = 0;\n    int ignore = 1;\n\n    ONV(fp == NULL, (\"could not open %s\", fname));\n\n    *out = NULL;\n\n    while (fgets(buf, sizeof buf, fp) != NULL) {\n        size_t len = strlen(buf) - 1;\n        \n        if (len < 1) continue;\n\n        /* look for the wrapper lines. */\n        if (strncmp(buf, \"-----\", 5) == 0) {\n            ignore = !ignore;\n            continue;\n        }\n\n        /* ignore until the first wrapper line */\n        if (ignore) continue;\n        \n        *out = realloc(*out, outlen + len + 1);\n        memcpy(*out + outlen, buf, len);\n        outlen += len;\n    }\n\n    (*out)[outlen] = '\\0';\n    fclose(fp);\n\n    return OK;\n}\n\n/* check export cert data 'actual' against expected data 'expected */\nstatic int check_exported_data(const char *actual, const char *expected)\n{\n    ONN(\"could not export cert\", actual == NULL);\n\n    ONN(\"export data contained newline\",\n        strchr(actual, '\\r') || strchr(actual, '\\n'));        \n\n    ONV(strcmp(actual, expected), (\"exported cert differed from expected:\\n\"\n                                   \"actual: %s\\nexpected: %s\", \n                                   actual, expected));\n    return OK;\n}\n\n/* Test import and export of certificates.  The export format is PEM\n * without the line feeds and wrapping; compare against . */\nstatic int import_export(void)\n{\n    char *expected, *actual;\n    ne_ssl_certificate *cert, *imp;\n\n    CALL(flatten_pem(\"server.cert\", &expected));\n    \n    cert = ne_ssl_cert_read(\"server.cert\");\n    ONN(\"could not load server.cert\", cert == NULL);\n\n    /* export the cert to and compare it with the PEM file */\n    actual = ne_ssl_cert_export(cert);\n    CALL(check_exported_data(actual, expected));\n\n    /* import the exported cert data, check it looks the same */\n    imp = ne_ssl_cert_import(actual);\n    ONN(\"failed to import exported cert\", imp == NULL);\n    ONN(\"imported cert was different to original\", \n        ne_ssl_cert_cmp(imp, cert));\n\n    /* re-export the imported cert and check that looks the same */\n    ne_free(actual);\n    actual = ne_ssl_cert_export(imp);\n    CALL(check_exported_data(actual, expected));\n    ne_ssl_cert_free(imp);\n\n    /* try importing from bogus data */\n    imp = ne_ssl_cert_import(\"!!\");\n    ONN(\"imported bogus cert from bogus base64\", imp != NULL);\n    imp = ne_ssl_cert_import(\"aaaa\");\n    ONN(\"imported bogus cert from valid base64\", imp != NULL);\n\n    ne_ssl_cert_free(cert);\n    ne_free(actual);\n    ne_free(expected);\n    return OK;\n}\n\n/* Test write/read */\nstatic int read_write(void)\n{\n    ne_ssl_certificate *c1, *c2;\n\n    c1 = ne_ssl_cert_read(\"server.cert\");\n    ONN(\"could not load server.cert\", c1 == NULL);\n\n    ONN(\"could not write output.pem\", ne_ssl_cert_write(c1, \"output.pem\"));\n    \n    ONN(\"wrote to nonexistent directory\",\n        ne_ssl_cert_write(c1, \"nonesuch/output.pem\") == 0);\n\n    c2 = ne_ssl_cert_read(\"output.pem\");\n    ONN(\"could not read output.pem\", c2 == NULL);\n    \n    ONN(\"read of output.pem differs from original\",\n        ne_ssl_cert_cmp(c2, c1));\n\n    ne_ssl_cert_free(c1);\n    ne_ssl_cert_free(c2);\n\n    return OK;\n}\n\n/* A verification callback which caches the passed cert. */\nstatic int verify_cache(void *userdata, int fs,\n                        const ne_ssl_certificate *cert)\n{\n    char **cache = userdata;\n    \n    if (*cache == NULL) {\n        *cache = ne_ssl_cert_export(cert);\n        return 0;\n    } else {\n        return -1;\n    }\n}\n\n/* Test a common use of the SSL API; cache the server cert across\n * sessions. */\nstatic int cache_cert(void)\n{\n    ne_session *sess;\n    char *cache = NULL;\n    ne_ssl_certificate *cert;\n    struct ssl_server_args args = {0};\n\n    args.cert = \"ssigned.pem\";\n    args.cache = 1;\n\n    CALL(make_ssl_session(&sess, \"localhost\", ssl_server, &args));\n    ne_ssl_set_verify(sess, verify_cache, &cache);\n    CALL(load_and_trust_cert(sess, CA_CERT));\n\n    ONREQ(any_request(sess, \"/foo\"));\n    CALL(destroy_and_wait(sess));\n\n    ONN(\"no cert was cached\", cache == NULL);\n    \n    /* make a real cert */\n    cert = ne_ssl_cert_import(cache);\n    ONN(\"could not import cached cert\", cert == NULL);\n    ne_free(cache);\n\n    /* create a new session */\n    CALL(make_ssl_session(&sess, \"localhost\", ssl_server, &args));\n    /* trust the cert */\n    ne_ssl_trust_cert(sess, cert);\n    ne_ssl_cert_free(cert);\n    /* now, the request should succeed without manual verification */\n    CALL(load_and_trust_cert(sess, CA_CERT));\n    ONREQ(any_request(sess, \"/foo\"));\n\n    return destroy_and_wait(sess);\n}\n\nstatic int nonssl_trust(void)\n{\n    ne_session *sess = ne_session_create(\"http\", \"www.example.com\", 80);\n    \n    ne_ssl_trust_cert(sess, def_ca_cert);\n    ne_ssl_trust_default_ca(sess);\n    \n    ne_session_destroy(sess);\n\n    return OK;\n}\n\n#ifdef HAVE_PAKCHOIS\n#define PINMAX (2)\nstruct pindata {\n    const char *password[PINMAX];\n    ne_buffer *trace;\n};\n\n/* PIN password provider callback. */\nstatic int pkcs11_pin(void *userdata, int attempt,\n                      const char *slot_descr, const char *token_label,\n                      unsigned int flags, char *pin)\n{\n    struct pindata *data = userdata;\n\n    NE_DEBUG(NE_DBG_SSL, \"pk11: slot = [%s], token = [%s]\\n\",\n             slot_descr, token_label);\n\n    ne_buffer_snprintf(data->trace, 200, \"pin(%d,%s,%s,%u)\\n\",\n                       attempt, slot_descr?slot_descr:\"[none]\",\n                       token_label?token_label:\"[none]\", flags);\n\n    if (attempt < PINMAX && data->password[attempt]) {\n        strcpy(pin, data->password[attempt]);\n        return 0;\n    }\n    else {\n        return -1;\n    }\n}\n\n#define SLOT_NSS \"NSS User Private Key and Certificate Services\"\n#define TOKEN_NSS \"NSS Certificate DB\"\n\nstatic int nss_pkcs11_test(const char *dbname)\n{\n    ne_session *sess;\n    struct ssl_server_args args = {SERVER_CERT, NULL};\n    ne_ssl_pkcs11_provider *prov;\n    struct pindata pindata;\n    int ret;\n\n    args.require_cc = 1;\n\n    if (access(dbname, R_OK|X_OK)) {\n        t_warning(\"NSS required for PKCS#11 testing\");\n        return SKIP;\n    }\n\n    ret = ne_ssl_pkcs11_nss_provider_init(&prov, \"softokn3\", dbname, NULL, \n                                          NULL, NULL);\n    if (ret) {\n        if (ret == NE_PK11_NOTIMPL)\n            t_context(\"pakchois library required for PKCS#11 support\");\n        else\n            t_context(\"could not load NSS softokn3 PKCS#11 provider\");\n        return SKIP;\n    }\n\n    pindata.password[0] = \"notfoobar\";\n    pindata.password[1] = \"foobar\";\n    pindata.trace = ne_buffer_create();\n\n    CALL(make_ssl_session(&sess, \"localhost\", ssl_server, &args));\n    CALL(load_and_trust_cert(sess, CA_CERT));\n\n    ne_ssl_pkcs11_provider_pin(prov, pkcs11_pin, &pindata);\n    ne_ssl_set_pkcs11_provider(sess, prov);\n\n    CALL(any_request(sess, \"/pkcs11\"));\n    CALL(destroy_and_wait(sess));\n    ne_ssl_pkcs11_provider_destroy(prov);\n\n    if (ret == OK)\n        ONCMPN(\"pin(0,\" SLOT_NSS \",\" TOKEN_NSS \",0)\\n\"\n               \"pin(1,\" SLOT_NSS \",\" TOKEN_NSS \",0)\\n\", pindata.trace->data, \"pin callback\", \"data\");\n    ne_buffer_destroy(pindata.trace);\n\n    return ret;\n}\n\nstatic int pkcs11(void)\n{\n    return nss_pkcs11_test(\"nssdb\");\n}\n#endif\n\nstatic int protovers(void)\n{\n    ne_session *sess;\n    struct ssl_server_args args = {SERVER_CERT, NULL};\n\n    args.minver = NE_SSL_PROTO_TLS_1_2;\n    args.maxver = NE_SSL_PROTO_TLS_1_2;\n\n    CALL(make_ssl_session(&sess, \"localhost\", ssl_server, &args));\n\n    ONV(ne_ssl_set_protovers(sess, args.minver, args.maxver),\n        (\"setting TLS protocol version failed: %s\", ne_get_error(sess)));\n\n    CALL(load_and_trust_cert(sess, CA_CERT));\n    CALL(any_request(sess, \"/foo\"));\n\n    return destroy_and_wait(sess);\n}\n\nstatic int notifier(void)\n{\n    ne_session *sess;\n    struct ssl_server_args args = {SERVER_CERT, NULL};\n    ne_buffer *buf = ne_buffer_create();\n\n    args.minver = NE_SSL_PROTO_TLS_1_2;\n    args.maxver = NE_SSL_PROTO_TLS_1_2;\n\n    CALL(make_ssl_session(&sess, \"localhost\", ssl_server, &args));\n\n    ONV(ne_ssl_set_protovers(sess, args.minver, args.maxver),\n        (\"setting TLS protocol version failed: %s\", ne_get_error(sess)));\n    ne_set_notifier(sess, sess_notifier, buf);\n    CALL(load_and_trust_cert(sess, CA_CERT));\n\n    CALL(any_request(sess, \"/notifier\"));\n\n    ONV(strstr(buf->data, \"-handshake(TLSv1.2, \") == NULL,\n        (\"missing/bad handshake() in notifier: %s\", buf->data));\n\n    ne_buffer_destroy(buf);\n    return destroy_and_wait(sess);\n}\n\n#define TEST_URI \"./enclient.pem\"\n\nstatic int clicert_uri(void)\n{\n    ne_session *sess;\n    struct ssl_server_args args = {SERVER_CERT, NULL};\n    ne_ssl_client_cert *cc;\n\n    args.require_cc = 1;\n\n    cc = ne_ssl_clicert_fromuri(TEST_URI, 0);\n    if (!cc && errno == ENOTSUP) {\n        t_context(\"client certificate URI support not available\");\n        return SKIP;\n    }\n    ONV(!cc, (\"could not load client certificate URI %s: %s\",\n              TEST_URI, strerror(errno)));\n\n    ONN(\"cc not in encrypted state\", !ne_ssl_clicert_encrypted(cc));\n    ONN(\"successful decrypt with bad password\",\n        ne_ssl_clicert_decrypt(cc, \"not-the-password\") == 0);\n    ONN(\"unsuccessful decrypt with good password\",\n        ne_ssl_clicert_decrypt(cc, P12_PASSPHRASE) != 0);\n\n    CALL(make_ssl_session(&sess, \"localhost\", ssl_server, &args));\n\n    ne_ssl_set_clicert(sess, cc);\n\n    CALL(load_and_trust_cert(sess, CA_CERT));\n    ONREQ(any_request(sess, \"/foo\"));\n\n    ne_ssl_clicert_free(cc);\n    return destroy_and_wait(sess);\n}\n\n/* TODO: code paths still to test in cert verification:\n * - server cert changes between connections: Mozilla gives\n * a \"bad MAC decode\" error for this; can do better?\n * - server presents no certificate (using ADH ciphers)... can\n * only really happen if they mess with the SSL_CTX and enable\n * ADH cipher manually; but good to check the failure case is \n * safe.\n * -  SSL cert changes between connections; handle as normal & re-verify\n * From the SSL book:\n * - an early FIN should be returned as a possible truncation attack,\n * NOT just an NE_SOCK_CLOSED.\n * - unexpected close_notify is an error but not an attack.\n * - never attempt session resumption after any aborted connection.\n */\n\nne_test tests[] = {\n    T_LEAKY(init),\n\n    T(load_server_certs),\n    T(trust_default_ca),\n\n    T(cert_fingerprint),\n    T(cert_hdigests),\n    T(cert_identities),\n    T(cert_validity),\n    T(cert_compare),\n    T(dname_compare),\n    T(dname_readable),\n    T(import_export),\n    T(read_write),\n\n    T(load_client_cert),\n    T(clicert_import),\n\n    T(simple),\n    T(simple_eof),\n    T(empty_truncated_eof),\n    T(fail_not_ssl),\n    T(cache_cert),\n    T(intermediary),\n\n    T(client_cert_pkcs12),\n    T(ccert_unencrypted),\n    T(client_cert_provided),\n    T(cc_provided_dnames),\n    T(no_client_cert),\n    T(client_cert_ca),\n\n    T(parse_cert),\n    T(parse_chain),\n\n    T(no_verify),\n    T(cache_verify),\n    T(wildcard_match),\n    T(wildcard_match_altname),\n    T(caseless_match),\n\n    T(subject_altname),\n    T(two_subject_altname),\n    T(two_subject_altname2),\n    T(notdns_altname),\n    T(ipaddr_altname),\n\n    T(multi_commonName),\n    T(commonName_first),\n\n    T(fail_wrongCN),\n    T(fail_expired),\n    T(fail_notvalid),\n    T(fail_untrusted_ca),\n    T(fail_self_signed),\n    T(fail_missing_CN),\n    T(fail_host_ipaltname),\n    T(fail_bad_ipaltname),\n    T(fail_wildcard),\n    T(fail_wildcard_ip),\n    T(fail_ca_notyetvalid),\n    T(fail_ca_expired),\n\n    T(nulcn_identity),\n#if 0\n    /* These certs were created with a SHA#1 digest so are rejected by\n     * modern TLS libraries. */\n    T(fail_nul_cn),\n    T(fail_nul_san),\n#endif\n\n    T(session_cache),\n\n    T(fail_tunnel),\n    T(proxy_tunnel),\n    T(auth_proxy_tunnel),\n    T(auth_tunnel_creds),\n    T(auth_tunnel_fail),\n\n    T(protovers),\n\n    T(nonssl_trust),\n\n#ifdef HAVE_PAKCHOIS\n    T(pkcs11),\n#endif\n    T(notifier),\n    T(clicert_uri),\n\n    T(NULL) \n};\n"
  },
  {
    "path": "test/string-tests.c",
    "content": "/* \n   String handling tests\n   Copyright (C) 2001-2007, 2009, Joe Orton <joe@manyfish.co.uk>\n\n   This program is free software; you can redistribute it and/or modify\n   it under the terms of the GNU General Public License as published by\n   the Free Software Foundation; either version 2 of the License, or\n   (at your option) any later version.\n  \n   This program is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU General Public License for more details.\n  \n   You should have received a copy of the GNU General Public License\n   along with this program; if not, write to the Free Software\n   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\n*/\n\n#include \"config.h\"\n\n#ifdef HAVE_STDLIB_H\n#include <stdlib.h>\n#endif\n#ifdef HAVE_STRING_H\n#include <string.h>\n#endif\n#ifdef HAVE_ERRNO_H\n#include <errno.h> /* for the ENOENT definitions in str_errors */\n#endif\n#ifdef HAVE_LIMITS_H\n#include <limits.h>\n#endif\n\n#include \"ne_string.h\"\n#include \"ne_utils.h\"\n\n#include \"tests.h\"\n\n#undef ONCMP\n#define ONCMP(a,b) ONV(!a || strcmp(a, b), \\\n\t\t       (\"result was [%s] not [%s]\", a, b))\n\nstatic int simple(void) {\n    ne_buffer *s = ne_buffer_create();\n    ON(s == NULL);\n    ne_buffer_zappend(s, \"abcde\");\n    ONCMP(s->data, \"abcde\");\n    ON(ne_buffer_size(s) != 5);\n    ne_buffer_destroy(s);\n    return OK;\n}\n\nstatic int buf_concat(void)\n{\n    ne_buffer *s = ne_buffer_create();\n    ON(s == NULL);\n    ne_buffer_concat(s, \"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", NULL);\n    ONCMP(s->data, \"abcdefg\");\n    ON(ne_buffer_size(s) != 7);\n    ne_buffer_destroy(s);\n    return OK;\n}\n\nstatic int buf_concat2(void)\n{\n#define RES \"alphabetagammadeltaepsilonetatheta\"\n    ne_buffer *s = ne_buffer_create();\n    ON(s == NULL);\n    ne_buffer_concat(s, \"alpha\", \"beta\", \"gamma\", \"delta\", \"epsilon\", \n\t\t     \"eta\", \"theta\", NULL);\n    ONCMP(s->data, RES);\n    ON(ne_buffer_size(s) != strlen(RES));\n    ne_buffer_destroy(s);\n    return OK;\n}\n\nstatic int buf_concat3(void)\n{\n    ne_buffer *s = ne_buffer_create();\n    ON(s == NULL);\n    ne_buffer_zappend(s, \"foobar\");\n    ne_buffer_concat(s, \"norman\", NULL);\n    ONCMP(s->data, \"foobarnorman\");\n    ON(ne_buffer_size(s) != 12);\n    ne_buffer_destroy(s);\n    return OK;\n}\n\nstatic int append(void)\n{\n    ne_buffer *s = ne_buffer_create();\n    ON(s == NULL);\n    ne_buffer_append(s, \"a\", 1);\n    ne_buffer_append(s, \"b\", 1);\n    ne_buffer_append(s, \"c\", 1);\n    ONCMP(s->data, \"abc\");\n    ON(ne_buffer_size(s) != 3);\n    ne_buffer_zappend(s, \"hello\");\n    ONCMP(s->data, \"abchello\");\n    ne_buffer_czappend(s, \"world\");\n    ONCMP(s->data, \"abchelloworld\");\n    ON(ne_buffer_size(s) != 13);\n    ne_buffer_destroy(s);\n    return OK;\n}    \n\nstatic int grow(void)\n{\n    ne_buffer *s = ne_buffer_ncreate(2);\n    ON(s == NULL);\n    ne_buffer_append(s, \"a\", 1);\n    ne_buffer_grow(s, 4);\n    ONCMP(s->data, \"a\");\n    ne_buffer_destroy(s);\n    return OK;\n}\n\nstatic int alter(void) {\n    ne_buffer *s = ne_buffer_create();\n    char *d;\n    ON(s == NULL);\n    ne_buffer_zappend(s, \"abcdefg\");\n    d = s->data;\n    ON(d == NULL);\n    d[2] = '\\0';\n    ne_buffer_altered(s);\n    ONCMP(s->data, \"ab\");\n    ON(ne_buffer_size(s) != 2);\n    ne_buffer_zappend(s, \"hijkl\");\n    ONCMP(s->data, \"abhijkl\");\n    ne_buffer_destroy(s);\n    return OK;\n}\n\n/* Macros for testing ne_token. */\n\n#define TEST(res) do { \\\n  char *tok = ne_token(&pnt, ','); \\\n  ONN(res \": return\", tok == NULL); \\\n  ONN(res \": compare\", strcmp(tok, (res))); \\\n  ONN(res \": modify\", pnt == NULL); \\\n} while (0)\n\n#define LASTTEST(res) do { \\\n  char *tok = ne_token(&pnt, ','); \\\n  ONN(res \": last return\", tok == NULL); \\\n  ONN(res \": last compare\", strcmp(tok, (res))); \\\n  ONN(res \": last modify\", pnt != NULL); \\\n} while (0)\n\n#define QTEST(res) do { \\\n  char *tok = ne_qtoken(&pnt, ',', QUOTES); \\\n  ONN(res \": return\", tok == NULL); \\\n  ONN(res \": compare\", strcmp(tok, (res))); \\\n  ONN(res \": modify\", pnt == NULL); \\\n} while (0)\n\n#define QLASTTEST(res) do { \\\n  char *tok = ne_qtoken(&pnt, ',', QUOTES); \\\n  ONN(res \": last return\", tok == NULL); \\\n  ONN(res \": last compare\", strcmp(tok, (res))); \\\n  ONN(res \": last modify\", pnt != NULL); \\\n} while (0)\n\nstatic int token1(void)\n{\n    char *str = ne_strdup(\"a,b,c,d\"), *pnt = str;\n\n    TEST(\"a\"); TEST(\"b\"); TEST(\"c\"); LASTTEST(\"d\");\n    \n    ne_free(str);\n    return OK;\n}\n\nstatic int token2(void)\n{\n    char *str = ne_strdup(\"norman,fishing, elsewhere\"), *pnt = str;\n    \n    TEST(\"norman\"); TEST(\"fishing\"); LASTTEST(\" elsewhere\");\n\n    ne_free(str);\n    return OK;\n}\n\nstatic int nulls(void)\n{\n    char *str = ne_strdup(\"alpha,,gamma\"), *pnt = str;\n\n    TEST(\"alpha\"); TEST(\"\"); LASTTEST(\"gamma\");\n    ne_free(str);\n    \n    pnt = str = ne_strdup(\",,,wooo\");\n    TEST(\"\"); TEST(\"\"); TEST(\"\"); LASTTEST(\"wooo\");\n    ne_free(str);\n\n    pnt = str = ne_strdup(\"wooo,,,\");\n    TEST(\"wooo\"); TEST(\"\"); TEST(\"\"); LASTTEST(\"\");\n    ne_free(str);    \n\n    return OK;\n}\n\nstatic int empty(void)\n{\n    char *str = ne_strdup(\"\"), *pnt = str;\n\n    LASTTEST(\"\");\n    ne_free(str);\n\n    return OK;\n}\n\n#undef QUOTES\n#define QUOTES \"'\"\n\nstatic int quoted(void)\n{\n    char *str = \n\tne_strdup(\"alpha,'beta, a fish called HELLO!?',sandwiches\");\n    char *pnt = str;\n    \n    QTEST(\"alpha\");\n    QTEST(\"'beta, a fish called HELLO!?'\");\n    QLASTTEST(\"sandwiches\");\n    \n    ne_free(str);\n    return OK;\n}\n\nstatic int badquotes(void)\n{\n    char *str = ne_strdup(\"alpha,'blah\"), *pnt = str;\n    \n    QTEST(\"alpha\");\n    ON(ne_qtoken(&pnt, ',', QUOTES) != NULL);\n    \n    ne_free(str);\n    return OK;\n}\n\n/* for testing ne_shave. */\n#undef TEST\n#define TEST(str, ws, res) do { \\\n  char *s = ne_strdup((str)); \\\n  char *r = ne_shave(s, (ws)); \\\n  ONN(\"[\" str \"]\", strcmp(r, (res))); \\\n  ne_free(s); \\\n} while (0)\n\nstatic int shave(void)\n{\n    TEST(\" b \", \" \", \"b\");\n    TEST(\"b\", \" \", \"b\");\n    TEST(\"   b    \", \" \", \"b\");\n    TEST(\"--bbb-----\", \"-\", \"bbb\");\n    TEST(\"hello, world    \", \" \", \"hello, world\");\n    TEST(\"<<><<<><<this is foo<<><<<<><<\", \"<>\", \"this is foo\");\n    TEST(\"09809812342347I once saw an helicopter0012312312398\", \"0123456789\",\n\t \"I once saw an helicopter\");\n    return OK;\n}\n\n/* Regression test for ne_shave call which should produce an empty\n * string. */\nstatic int shave_regress(void)\n{\n    TEST(\"\\\"\\\"\", \"\\\"\", \"\");\n    return OK;\n}\n\n/* Test the ne_token/ne_shave combination. */\n\n#undef TEST\n#undef LASTTEST\n\n#define TEST(res) do { \\\n  char *tok = ne_token(&pnt, ','); \\\n  ONN(res \": return\", tok == NULL); \\\n  tok = ne_shave(tok, \" \"); \\\n  ONN(res \": shave\", tok == NULL); \\\n  ONN(res \": compare\", strcmp(tok, (res))); \\\n  ONN(res \": modify\", pnt == NULL); \\\n} while (0)\n\n\n#define LASTTEST(res) do { \\\n  char *tok = ne_token(&pnt, ','); \\\n  ONN(res \": last return\", tok == NULL); \\\n  tok = ne_shave(tok, \" \"); \\\n  ONN(res \": last shave\", tok == NULL); \\\n  ONN(res \": last compare\", strcmp(tok, (res))); \\\n  ONN(res \": last modify\", pnt != NULL); \\\n} while (0)\n\n/* traditional use of ne_token/ne_shave. */\nstatic int combo(void)\n{\n    char *str = ne_strdup(\"  fred , mary, jim , alice, david\"), *pnt = str;\n    \n    TEST(\"fred\"); TEST(\"mary\"); TEST(\"jim\"); TEST(\"alice\");\n    LASTTEST(\"david\");\n    \n    ne_free(str);\n    return 0;\n}\n\nstatic int concat(void)\n{\n#define CAT(res, args) do { char *str = ne_concat args; \\\nONCMP(str, res); \\\nne_free(str); } while (0)\n    CAT(\"alphabeta\", (\"alpha\", \"beta\", NULL));\n    CAT(\"alpha\", (\"alpha\", \"\", \"\", NULL));\n    CAT(\"\", (\"\", NULL));\n    CAT(\"\", (\"\", \"\", \"\", NULL));\n    CAT(\"alpha\", (\"\", \"a\", \"lph\", \"\", \"a\", NULL));\n    return OK;    \n}\n\nstatic int str_errors(void)\n{\n    char expect[200], actual[200];\n    \n    strncpy(expect, strerror(ENOENT), sizeof(expect)-1);\n    ONN(\"ne_strerror did not return passed-in buffer\",\n\tne_strerror(ENOENT, actual, sizeof(actual)) != actual);\n    \n    ONV(strcmp(expect, actual), \n\t(\"error from ENOENT was `%s' not `%s'\", actual, expect));\n\n    /* Test truncated error string is still NUL-terminated. */\n    ne_strerror(ENOENT, actual, 6);\n    NE_DEBUG(NE_DBG_HTTP, \"error: %s\\n\", actual);\n    ONN(\"truncated string had wrong length\", strlen(actual) != 5);\n\n    ne_strerror(-1, actual, 6);\n    ONN(\"truncated string for bad error had wrong length\", \n        strlen(actual) != 5);\n\n    return OK;\n}\n\nstatic int strnzcpy(void)\n{\n    char buf[16];\n\n    ne_strnzcpy(buf, \"abcdefghi\", 5);\n    ONV(strcmp(buf, \"abcd\"), (\"result was `%s' not `abcd'\", buf));\n    \n    ne_strnzcpy(buf, \"ab\", 5);\n    ONV(strcmp(buf, \"ab\"), (\"result was `%s' not `ab'\", buf));    \n\n    return OK;    \n}\n\n#define FOX_STRING \"The quick brown fox jumped over the lazy dog\"\n#define PUNC_STRING \"<>,.;'#:@~[]{}!\\\"$%^&*()_+-=\"\n\nstatic int cleaner(void)\n{\n    static const char *strings[] = {\n        \"alpha\", \"alpha\",\n        \"pretty\\033[41mcolours\", \"pretty [41mcolours\",\n        \"beta\\n\", \"beta \",\n        \"del\\rt\\na\", \"del t a\",\n        FOX_STRING, FOX_STRING,\n        \"0123456789\", \"0123456789\",\n        PUNC_STRING, PUNC_STRING,\n        \"\\01blah blee\\05bloo\", \" blah blee bloo\",\n        NULL,\n    };\n    unsigned int n;\n    \n    for (n = 0; strings[n]; n+=2) {\n        char *act = ne_strclean(ne_strdup(strings[n]));\n        \n        ONV(strcmp(act, strings[n+1]), \n            (\"cleansed to `%s' not `%s'\", act, strings[n+1]));\n        \n        ne_free(act);\n    }\n\n    return OK;\n}\n\n/* Check that raw data 'raw', of length 'len', has base64 encoding\n * of 'expected'. */\nstatic int b64_check(const unsigned char *raw, size_t len,\n                     const char *expected)\n{\n    char *encoded = ne_base64(raw, len);\n    unsigned char *decoded;\n    size_t dlen;\n    \n    ONV(strcmp(encoded, expected), \n        (\"base64(\\\"%s\\\") gave \\\"%s\\\" not \\\"%s\\\"\", raw, encoded, expected));\n    \n    dlen = ne_unbase64(encoded, &decoded);\n    ONV(dlen != len, \n        (\"decoded `%s' length was %\" NE_FMT_SIZE_T \" not %\" NE_FMT_SIZE_T,\n         expected, dlen, len));\n\n    ONV(memcmp(raw, decoded, dlen), \n        (\"decoded `%s' as `%.*s' not `%.*s'\",\n         expected, (int)dlen, decoded, (int)dlen, raw));\n\n    ne_free(decoded);\n    ne_free(encoded);\n    return OK;\n}\n\n/* ALLBITS: base64 encoding of \"\\0..\\377\" */\n#define ALLBITS \\\n\"AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKiss\" \\\n\"LS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZ\" \\\n\"WltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWG\" \\\n\"h4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKz\" \\\n\"tLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g\" \\\n\"4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w==\"\n\nstatic int base64(void)\n{\n    unsigned char bits[256];\n    size_t n;\n\n#define B64B(x, l, y) CALL(b64_check((unsigned char *)x, l, y))\n#define B64(x, y) B64B(x, strlen(x), y)\n\n    /* invent these with \n     *  $ printf \"string\" | uuencode -m blah\n     */\n    B64(\"a\", \"YQ==\");\n    B64(\"bb\", \"YmI=\");\n    B64(\"ccc\", \"Y2Nj\");\n    B64(\"Hello, world\", \"SGVsbG8sIHdvcmxk\");\n    B64(\"Aladdin:open sesame\", \"QWxhZGRpbjpvcGVuIHNlc2FtZQ==\");\n    B64(\"I once saw a dog called norman.\\n\", \n\t\"SSBvbmNlIHNhdyBhIGRvZyBjYWxsZWQgbm9ybWFuLgo=\");\n    B64(\"The quick brown fox jumped over the lazy dog\", \n\t\"VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wZWQgb3ZlciB0aGUgbGF6eSBkb2c=\");\n\n    /* binary data..\n     *   $ printf \"string\" | wc -c # get the length\n     *   $ printf \"string\" | uuencode -m blah # get the base64\n     */\n    B64B(\"\\0\\0\\0\\0\\0\\n\", 6, \"AAAAAAAK\");\n    B64B(\"I once wished \\0 upon a \\0 fish.\", 30, \n\t \"SSBvbmNlIHdpc2hlZCAAIHVwb24gYSAAIGZpc2gu\");\n    B64B(\"\\201\\202\\203\\204\", 4, \"gYKDhA==\");\n\n    for (n = 0; n < sizeof bits; n++)\n        bits[n] = (unsigned char)n;\n    CALL(b64_check(bits, sizeof bits, ALLBITS));\n\n#undef B64\n#undef B64B\n    return OK;\n}\n\nstatic int unbase64(void)\n{\n    static const char *ts[] = {\n        \"\", \"a\", \"ab\", \"abc\", \n        \"}bcd\", \"a}cd\", \"ab}d\", \"abc}\", \"    \",\n        \"^bcd\", \"a^cd\", \"ab^d\", \"abc^\",\n        \"====\", \"=bcd\", \"a=cd\", \"ab=d\", \"a==d\", \"a=c=\",\n        NULL\n    };\n    size_t n;\n\n    for (n = 0; ts[n]; n++) {\n        unsigned char *tmp;\n        ONV(ne_unbase64(ts[n], &tmp) != 0,\n            (\"invalid string `%s' was decoded\", ts[n]));\n    }\n\n    return OK;\n}\n\nstatic int printing(void)\n{\n    struct {\n        const char *in, *out;\n        size_t pass, ret;\n    } ts[] = {\n        { \"alpha\", \"alpha\", 10, 5 },\n        { \"alpha\", \"alph\", 5, 4 },\n        { \"foobar\", \"\", 1, 0 },\n        { NULL, NULL, 0, 0}\n    };\n    size_t n;\n\n    for (n = 0; ts[n].in; n++) {\n        char buf[512];\n        size_t ret;\n\n        memset(buf, 'A', sizeof buf);\n\n        ret = ne_snprintf(buf, ts[n].pass, \"%s\", ts[n].in);\n        \n        ONCMP(ts[n].out, buf);\n        ONV(ret != ts[n].ret, \n            (\"got return value %\" NE_FMT_SIZE_T \" not %\" NE_FMT_SIZE_T,\n             ret, ts[n].ret));\n\n        /* byte past the NUL must still be 'A' */\n        ONN(\"buffer over-ran!\", buf[ret + 1] != 'A');\n    }\n    \n    return OK;\n}\n\nstatic int casecmp(void)\n{\n    static const struct {\n        const char *left, *right;\n        int expect;\n    } ts[] = {\n        { \"abcdefghijklmnopqrstuvwxyz\", \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\", 0 },\n        { \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\", \"abcdefghijklmnopqrstuvwxyz\", 0 },\n        { \"foo\", \"bar\", 1 },\n        { \"!#:[@\\377\", \"!#:[@\\377\", 0 },\n        { \"bar\", \"foo\", -1 },\n        { \"foop\", \"foo\", 1 },\n        { \"foo\", \"foop\", -1 },\n        { NULL, NULL, 0 }\n    };\n    size_t n;\n    \n    for (n = 0; ts[n].left; n++) {\n        int actual;\n\n        actual = ne_strcasecmp(ts[n].left, ts[n].right);\n        \n        ONV(ts[n].expect == 0 && actual != 0,\n            (\"strcasecmp(%s, %s) gave %d, expected 0\",\n             ts[n].left, ts[n].right, actual));\n\n        ONV(ts[n].expect > 0 && actual <= 0,\n            (\"strcasecmp(%s, %s) gave %d, expected > 0\",\n             ts[n].left, ts[n].right, actual));\n\n        ONV(ts[n].expect < 0 && actual >= 0,\n            (\"strcasecmp(%s, %s) gave %d, expected < 0\",\n             ts[n].left, ts[n].right, actual));\n    }\n\n    ONN(\"comparison of identical pointers did not give zero\",\n        ne_strcasecmp(ts[0].left, ts[0].left) != 0);\n\n    return OK;\n}\n\nstatic int casencmp(void)\n{\n    static const struct {\n        const char *left, *right;\n        size_t n;\n        int expect;\n    } ts[] = {\n        { \"abcdefghijklmnopqrstuvwxyz\", \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\", 30, 0 },\n        { \"abcdefghijklmnopqrstuvwxyz\", \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\", 10, 0 }, \n        { \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\", \"abcdefghijklmnopqrstuvwxyz\", 0, 0 },\n        { \"foo\", \"bar\", 3, 1 },\n        { \"bar\", \"foo\", 4, -1 },\n        { \"bar\", \"foo\", 3, -1 },\n        { \"foop\", \"foo\", 4, 1 },\n        { \"foo\", \"foop\", 4, -1 },\n        { \"bee\", \"bar\", 0, 0},\n        { NULL, NULL, 0, 0 }\n    };\n    size_t n;\n    \n    for (n = 0; ts[n].left; n++) {\n        int actual;\n\n        actual = ne_strncasecmp(ts[n].left, ts[n].right, ts[n].n);\n        \n        ONV(ts[n].expect == 0 && actual != 0,\n            (\"strncasecmp(%s, %s, %\" NE_FMT_SIZE_T \") gave %d, expected 0\",\n             ts[n].left, ts[n].right, ts[n].n, actual));\n\n        ONV(ts[n].expect > 0 && actual <= 0,\n            (\"strncasecmp(%s, %s, %\" NE_FMT_SIZE_T \") gave %d, expected > 0\",\n             ts[n].left, ts[n].right, ts[n].n, actual));\n\n        ONV(ts[n].expect < 0 && actual >= 0,\n            (\"strncasecmp(%s, %s, %\" NE_FMT_SIZE_T \") gave %d, expected < 0\",\n             ts[n].left, ts[n].right, ts[n].n, actual));\n    }\n\n    ONN(\"comparison of identical pointers did not give zero\",\n        ne_strncasecmp(ts[0].left, ts[0].left, 5) != 0);\n\n    return OK;\n}\n\nstatic int buf_print(void)\n{\n    ne_buffer *buf = ne_buffer_create();\n\n    ne_buffer_czappend(buf, \"foo-\");\n    ne_buffer_snprintf(buf, 20, \"bar-%s-asda\", \"norman\");\n    ne_buffer_czappend(buf, \"-bloo\");\n    ONN(\"snprintf return value\", ne_buffer_snprintf(buf, 2, \"---\") != 1);\n    \n    ONCMP(buf->data, \"foo-bar-norman-asda-bloo-\");\n\n    ne_buffer_destroy(buf);\n    \n    return OK;\n}\n\nstatic int qappend(void)\n{\n    static const struct {\n        const char *in;\n        size_t inlen;\n        const char *out;\n    } ts[] = {\n        { \"\", 0, \"\" },\n        { \"a\", 1, \"a\" },\n        { \"b\", 2, \"b\\\\x00\" },\n        { \"alpha\\0alpha\", 11, \"alpha\\\\x00alpha\" },\n        { \"a\\tb\", 3, \"a\\\\x09b\" },\n        { \"foo\\x7f\" \"bar\", 7, \"foo\\\\x7fbar\" },\n        { NULL }\n    };\n    unsigned n;\n\n    for (n = 0; ts[n].in; n++) {\n        ne_buffer *buf = ne_buffer_create();\n        char *s;\n        const unsigned char *in = (const unsigned char *)ts[n].in;\n\n        ne_buffer_qappend(buf, in, ts[n].inlen);\n\n        ONCMP(buf->data, ts[n].out);\n\n        ONV(strlen(buf->data) + 1 != buf->used,\n            (\"bad buffer length for '%s': %\" NE_FMT_SIZE_T, \n             ts[n].out, buf->used));\n        \n        s = ne_strnqdup(in, ts[n].inlen);\n        \n        ONCMP(s, ts[n].out);\n\n        ne_free(s);\n        ne_buffer_destroy(buf);\n    }\n\n    return OK;\n}\n\nstatic char *test_vstrhash(unsigned int flags, ...)\n{\n    va_list ap;\n    char *rv;\n\n    va_start(ap, flags);\n    rv = ne_vstrhash(flags, ap);\n    va_end(ap);\n\n    return rv;\n}\n\n#define TEST1 \"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq\"\n#define TEST1_SHA \"248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1\"\n\n#define ONVEC(args, expect) \\\n    do { char *h = ne_strhash args; ONCMP(h, expect); ne_free(h); } while (0)\n\nstatic int strhash(void)\n{\n    ONN(\"zero flags must return NULL\", ne_strhash(0, \"\", NULL) != NULL);\n    ONN(\"zero flags must return NULL for vstrhash\", test_vstrhash(0, \"\", NULL) != NULL);\n\n    ONN(\"no alg flags must return NULL\", ne_strhash(NE_HASH_COLON, \"\", NULL) != NULL);\n    ONN(\"no alg flags must return NULL\", ne_strhash(NE_HASH_SPACE, \"\", NULL) != NULL);\n    \n    ONVEC((NE_HASH_MD5, \"\", NULL), \"d41d8cd98f00b204e9800998ecf8427e\");\n    ONVEC((NE_HASH_MD5, \"foo\", \"ba\", \"r\", NULL), \"3858f62230ac3c915f300c664312c63f\");\n    ONVEC((NE_HASH_MD5|NE_HASH_SPACE, \"foo\", \"ba\", \"r\", NULL), \"38 58 f6 22 30 ac 3c 91 5f 30 0c 66 43 12 c6 3f\");\n\n    return OK;\n}\n\nstatic int strhash_sha_256(void)\n{\n    char *p = ne_strhash(NE_HASH_SHA256, \"\", NULL);\n    if (p == NULL) {\n        t_context(\"SHA-2-256 not supported\");\n        return SKIP;\n    }\n    ne_free(p);\n\n    ONVEC((NE_HASH_SHA256, TEST1, NULL), TEST1_SHA);\n    ONVEC((NE_HASH_SHA256, \"foobar\", \"foo\", \"bar\", \"f\", \"oobar\", NULL),\n          \"d173c93898d3ca8455a4526e0af2a1aee9b91c8ec19adac16e6e8be2da09436c\");\n\n    return OK;\n}\n\n/* NIST examples from https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/SHA512.pdf */\n#define TEST1_512 \"abc\"\n#define TEST1_512_MDC \"dd:af:35:a1:93:61:7a:ba:cc:41:73:49:ae:20:41:31:12:e6:fa:4e:89:a9:7e:a2:0a:9e:ee:e6:4b:55:d3:9a:21:92:99:2a:27:4f:c1:a8:36:ba:3c:23:a3:fe:eb:bd:45:4d:44:23:64:3c:e8:0e:2a:9a:c9:4f:a5:4c:a4:9f\"\n#define TEST2_512_1 \"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrl\"\n#define TEST2_512_2 \"mnopqrsmnopqrstnopqrstu\"\n#define TEST2_512_MD \"8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909\"\n\n\n/* NIST examples from https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/SHA512_256.pdf */\n#define TEST1_512_256 \"abc\"\n#define TEST1_512_256_MD \"53048e2681941ef99b2e29b76b4c7dabe4c2d0c634fc6d46e0e2f13107e7af23\"\n#define TEST2_512_256_1 \"abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijkl\"\n#define TEST2_512_256_2 \"mnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu\"\n#define TEST2_512_256_MD \"3928e184fb8690f840da3988121d31be65cb9d3ef83ee6146feac861e19b563a\"\n#define TEST2_512_256_MDC \"39:28:e1:84:fb:86:90:f8:40:da:39:88:12:1d:31:be:65:cb:9d:3e:f8:3e:e6:14:6f:ea:c8:61:e1:9b:56:3a\"\n\nstatic int strhash_sha_512(void)\n{\n    char *p = ne_strhash(NE_HASH_SHA512, \"\", NULL);\n\n    if (p == NULL) {\n        t_context(\"SHA-2-512 not supported\");\n        return SKIP;\n    }\n    ne_free(p);\n\n    ONVEC((NE_HASH_SHA512|NE_HASH_COLON, TEST1_512, NULL), TEST1_512_MDC);\n    ONVEC((NE_HASH_SHA512, TEST2_512_1, TEST2_512_2, NULL), TEST2_512_MD);\n\n    return OK;\n}\n\nstatic int strhash_sha_512_256(void)\n{\n    char *p = ne_strhash(NE_HASH_SHA512_256, \"\", NULL);\n\n    if (p == NULL) {\n        t_context(\"SHA-2-512/256 not supported\");\n        return SKIP;\n    }\n    ne_free(p);\n\n    ONVEC((NE_HASH_SHA512_256, TEST1_512_256, NULL), TEST1_512_256_MD);\n    ONVEC((NE_HASH_SHA512_256, TEST2_512_256_1, TEST2_512_256_2, NULL), TEST2_512_256_MD);\n    ONVEC((NE_HASH_SHA512_256|NE_HASH_COLON, TEST2_512_256_1, TEST2_512_256_2, NULL),\n          TEST2_512_256_MDC);\n\n    return OK;\n}\n\n/* FIPS 180-1 standard SHA-1 test vectors from RFC 3174 */\n#define TEST1_SHA1 \"abc\"\n#define TEST1_SHA1_MD \"a9993e364706816aba3e25717850c26c9cd0d89d\"\n#define TEST2_SHA1 \"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq\"\n#define TEST2_SHA1_MD \"84983e441c3bd26ebaae4aa1f95129e5e54670f1\"\n#define TEST2_SHA1_MDC \"84:98:3e:44:1c:3b:d2:6e:ba:ae:4a:a1:f9:51:29:e5:e5:46:70:f1\"\n\nstatic int strhash_sha1(void)\n{\n    char *p = ne_strhash(NE_HASH_SHA1, \"\", NULL);\n\n    if (p == NULL) {\n        t_context(\"SHA-1 not supported\");\n        return SKIP;\n    }\n    ne_free(p);\n\n    /* Test vector 1: \"abc\" */\n    ONVEC((NE_HASH_SHA1, TEST1_SHA1, NULL), TEST1_SHA1_MD);\n\n    /* Test vector 2: \"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq\" */\n    ONVEC((NE_HASH_SHA1, TEST2_SHA1, NULL), TEST2_SHA1_MD);\n\n    /* Test with colon formatting */\n    ONVEC((NE_HASH_SHA1|NE_HASH_COLON, TEST2_SHA1, NULL), TEST2_SHA1_MDC);\n\n    /* Test with multiple string arguments */\n    ONVEC((NE_HASH_SHA1, \"a\", \"b\", \"c\", NULL), TEST1_SHA1_MD);\n\n    /* Test empty string - da39a3ee5e6b4b0d3255bfef95601890afd80709 */\n    ONVEC((NE_HASH_SHA1, \"\", NULL), \"da39a3ee5e6b4b0d3255bfef95601890afd80709\");\n\n    return OK;\n}\n\nstatic int strparam(void)\n{\n    static const struct {\n        const char *charset, *lang;\n        const char *value;\n        const char *expect;\n    } ts[] = {\n        { \"UTF-8\", NULL, \"foobar\", NULL },\n        { \"UTF-8\", NULL, \"foo12345bar\", NULL },\n        { \"UTF-8\", NULL, \"foo@bar\", \"UTF-8''foo%40bar\" },\n        { \"UTF-8\", NULL, \"foo bar\", \"UTF-8''foo%20bar\" },\n        { \"iso-8859-1\", \"en\", \"\\xA3 rates\", \"iso-8859-1'en'%a3%20rates\" },\n        { \"UTF-8\", NULL, \"£ and € rates\", \"UTF-8''%c2%a3%20and%20%e2%82%ac%20rates\" },\n        { NULL }\n    };\n    unsigned n;\n\n    for (n = 0; ts[n].charset; n++) {\n        char *act = ne_strparam(ts[n].charset, ts[n].lang, (const unsigned char *)ts[n].value);\n\n        if (ts[n].expect == NULL) {\n            ONV(act != NULL, (\"expected NULL output for '%s', got '%s'\",\n                              ts[n].value, act));\n        }\n        else {\n            ONCMP(act, ts[n].expect);\n            ne_free(act);\n        }\n    }\n\n    return OK;\n}\n\nstatic int strhextoul(void)\n{\n    static const struct {\n        const char *input;\n        unsigned long expect;\n        int error; /* errno */\n        const char *endp;\n    } *t, ts[] = {\n        { \"0x0\", ULONG_MAX, EINVAL },\n        { \"0X1\", ULONG_MAX, EINVAL },\n        { \"+1\", ULONG_MAX, EINVAL },\n        { \"-0\", ULONG_MAX, EINVAL },\n        { \"+0x1\", ULONG_MAX, EINVAL },\n        { \"+0X1\", ULONG_MAX, EINVAL },\n        { \"\", ULONG_MAX, EINVAL },\n        { \"1\", 1, 0, \"\" },\n        { \" 10\", ULONG_MAX, EINVAL, \" 10\" },\n        { \"0000010 \", 16, 0, \" \" },\n        { \"4242\", 16962, 0 },\n        { \"4242zZZz\", 16962, 0, \"zZZz\" },\n        { \"cAfEBeEf\", 3405692655 },\n#if SIZEOF_LONG == 8\n        { \"10000000000000000\", ULONG_MAX, ERANGE },\n        { \"100000000\", 0x100000000, 0 },\n#elif SIZEOF_LONG == 4\n        { \"100000000\", ULONG_MAX, ERANGE },\n#endif\n        { NULL }\n    };\n    unsigned n;\n\n    for (n = 0; ts[n].input; n++) {\n        unsigned long actual;\n        const char *endp = \"(unset)\", **endpp;\n        int errnum;\n\n        t = ts + n;\n\n        endpp = t->endp ? &endp : NULL;\n        errno = ENOENT;\n        actual = ne_strhextoul(t->input, endpp);\n        errnum = errno;\n        ONV(errnum != t->error,\n            (\"got errno %d not %d for [%s]\", errnum, t->error, t->input));\n        ONV(actual != t->expect,\n            (\"got %lu not %lu for [%s]\", actual, t->expect, t->input));\n        if (endpp) ONCMP(*endpp, t->endp);\n    }\n\n    return OK;\n}\n\nstatic int strlower(void)\n{\n    char buf[256];\n\n    ne_strnzcpy(buf, \"HELLO\", sizeof buf);\n    ONN(\"unexpected return value\", ne_strlower(buf) != buf);\n    ONV(strcmp(buf, \"hello\"), (\"strlower failed: got %s\", buf));\n\n    ne_strnzcpy(buf, \"MiXeD CaSe 123\", sizeof buf);\n    ne_strlower(buf);\n    ONV(strcmp(buf, \"mixed case 123\"), (\"strlower failed: got %s\", buf));\n\n    ne_strnzcpy(buf, \"already lower\", sizeof buf);\n    ne_strlower(buf);\n    ONV(strcmp(buf, \"already lower\"), (\"strlower failed: got %s\", buf));\n\n    ne_strnzcpy(buf, \"\", sizeof buf);\n    ne_strlower(buf);\n    ONV(strcmp(buf, \"\"), (\"strlower failed on empty string\"));\n\n    return OK;\n}\n\nstatic int strupper(void)\n{\n    static const struct {\n        const char *input;\n        const char *expected;\n    } ts[] = {\n        { \"hello\", \"HELLO\" },\n        { \"MiXeD CaSe 123\", \"MIXED CASE 123\" },\n        { \"ALREADY UPPER\", \"ALREADY UPPER\" },\n        { \"\", \"\" },\n        { NULL, NULL }\n    };\n    unsigned int i;\n\n    for (i = 0; ts[i].input != NULL; i++) {\n        char buf[256];\n\n        ne_strnzcpy(buf, ts[i].input, sizeof buf);\n        \n        ONN(\"unexpected return value\", ne_strupper(buf) != buf);\n        ONV(strcmp(buf, ts[i].expected),\n            (\"strupper failed: got %s, expected %s\", buf, ts[i].expected));\n    }\n\n    return OK;\n}\n\nstatic int mknonce(void)\n{\n    size_t ts[3] = {16, 32, 64};\n    unsigned int n;\n\n    for (n = 0; n < sizeof(ts)/sizeof(ts[0]); n++) {\n        unsigned char nonce1[256], nonce2[256];\n\n        ONN(\"nonce generation failed\", ne_mknonce(nonce1, ts[n], 0));\n        ONN(\"second nonce generation failed\", ne_mknonce(nonce2, ts[n], 0));\n        ONV(memcmp(nonce1, nonce2, ts[0]) == 0,\n            (\"two consecutive nonces are identical\"));\n    }\n\n    return OK;\n}\n\n/* Test multiple nonces for uniqueness */\nstatic int mknonce_uniqueness(void)\n{\n    unsigned char nonces[10][16];\n    unsigned int i, j;\n\n    /* Generate 10 nonces */\n    for (i = 0; i < 10; i++)\n        ONN(\"nonce generation failed\", ne_mknonce(nonces[i], sizeof nonces[i], 0));\n\n    /* Check all are unique */\n    for (i = 0; i < 10; i++)\n        for (j = i + 1; j < 10; j++)\n            ONV(memcmp(nonces[i], nonces[j], sizeof nonces[i]) == 0,\n                (\"nonces at positions %u and %u are identical\",\n                 i, j));\n\n    return OK;\n}\n\nne_test tests[] = {\n    T(simple),\n    T(buf_concat),\n    T(buf_concat2),\n    T(buf_concat3),\n    T(append),\n    T(grow),\n    T(alter),\n    T(token1),\n    T(token2),\n    T(nulls),\n    T(empty),\n    T(quoted),\n    T(badquotes),\n    T(shave),\n    T(shave_regress),\n    T(combo),\n    T(concat),\n    T(str_errors),\n    T(strnzcpy),\n    T(cleaner),\n    T(base64),\n    T(unbase64),\n    T(printing),\n    T(casecmp),\n    T(casencmp),\n    T(buf_print),\n    T(qappend),\n    T(strhash),\n    T(strhash_sha1),\n    T(strhash_sha_256),\n    T(strhash_sha_512),\n    T(strhash_sha_512_256),\n    T(strparam),\n    T(strhextoul),\n    T(strlower),\n    T(strupper),\n    T(mknonce),\n    T(mknonce_uniqueness),\n    T(NULL)\n};\n\n"
  },
  {
    "path": "test/stubs.c",
    "content": "/* \n   neon test suite\n   Copyright (C) 2002-2005, Joe Orton <joe@manyfish.co.uk>\n\n   This program is free software; you can redistribute it and/or modify\n   it under the terms of the GNU General Public License as published by\n   the Free Software Foundation; either version 2 of the License, or\n   (at your option) any later version.\n  \n   This program is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU General Public License for more details.\n  \n   You should have received a copy of the GNU General Public License\n   along with this program; if not, write to the Free Software\n   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\n*/\n\n/** These tests show that the stub functions produce appropriate\n * results to provide ABI-compatibility when a particular feature is\n * not supported by the library.\n **/\n\n#include \"config.h\"\n\n#include <sys/types.h>\n\n#ifdef HAVE_STDLIB_H\n#include <stdlib.h>\n#endif\n#ifdef HAVE_UNISTD_H\n#include <unistd.h>\n#endif\n\n#include \"ne_request.h\"\n#include \"ne_socket.h\"\n#include \"ne_compress.h\"\n#include \"ne_pkcs11.h\"\n\n#include \"tests.h\"\n#include \"child.h\"\n#include \"utils.h\"\n\n#if defined(NE_HAVE_ZLIB) && defined(NE_HAVE_SSL) && defined(HAVE_PAKCHOIS)\n#define NO_TESTS 1\n#endif\n\n#define EOL \"\\r\\n\"\n\n#ifndef NE_HAVE_ZLIB\nstatic int sd_result = OK;\n\nstatic int sd_reader(void *ud, const char *block, size_t len)\n{\n    const char *expect = ud;\n    if (strncmp(expect, block, len) != 0) {\n\tsd_result = FAIL;\n\tt_context(\"decompress reader got bad data\");\n    }\n    return 0;\n}\n\nstatic int stub_decompress(void)\n{\n    ne_session *sess;\n    ne_decompress *dc;\n    ne_request *req;\n    int ret;\n\n    CALL(make_session(&sess, single_serve_string, \n\t\t      \"HTTP/1.1 200 OK\" EOL\n\t\t      \"Connection: close\" EOL EOL\n\t\t      \"abcde\"));\n    \n    req = ne_request_create(sess, \"GET\", \"/foo\");\n\n    dc = ne_decompress_reader(req, ne_accept_2xx, sd_reader, \"abcde\");\n    \n    ret = ne_request_dispatch(req);\n    \n    CALL(await_server());\n    \n    ONREQ(ret);\n\n    ne_decompress_destroy(dc);\n    ne_request_destroy(req);\n    ne_session_destroy(sess);\n\n    /* This is a skeleton test suite file. */\n    return sd_result;\n}\n#endif\n\n#ifndef NE_HAVE_SSL\nstatic int stub_ssl(void)\n{\n    ne_session *sess = ne_session_create(\"https\", \"localhost\", 1234);\n    ne_ssl_certificate *cert;\n    ne_ssl_client_cert *cc;\n    ne_ssl_context *ctx;\n\n    /* these should all fail when SSL is not supported. */\n    cert = ne_ssl_cert_read(\"Makefile\");\n    if (cert) {\n        char *dn, digest[60], date[NE_SSL_VDATELEN];\n        const ne_ssl_certificate *issuer;\n\n        /* This branch should never be executed, but lets pretend it\n         * will to prevent the compiler optimising this code away if\n         * it's placed after the cert != NULL test.  And all that\n         * needs to be tested is that these functions link OK. */\n        dn = ne_ssl_readable_dname(ne_ssl_cert_subject(cert));\n        ONN(\"this code shouldn't run\", dn != NULL);\n        dn = ne_ssl_readable_dname(ne_ssl_cert_issuer(cert));\n        ONN(\"this code shouldn't run\", dn != NULL);\n        issuer = ne_ssl_cert_signedby(cert);\n        ONN(\"this code shouldn't run\", issuer != NULL);\n        ONN(\"this code shouldn't run\", ne_ssl_cert_digest(cert, digest));\n        ne_ssl_cert_validity(cert, date, date);\n        ONN(\"this code shouldn't run\",\n            ne_ssl_dname_cmp(ne_ssl_cert_subject(cert),\n                             ne_ssl_cert_issuer(cert)));\n        ONN(\"this code shouldn't run\", ne_ssl_cert_identity(issuer) != NULL);\n        ONN(\"this code shouldn't run\", ne_ssl_cert_export(cert) != NULL);\n        ONN(\"this code shouldn't run\", ne_ssl_cert_hdigest(cert, NE_HASH_MD5) != NULL);\n    }\n\n    ONN(\"this code shouldn't run\", ne_ssl_cert_import(\"foo\") != NULL);\n    ONN(\"this code shouldn't run\", ne_ssl_cert_read(\"Makefile\") != NULL);\n    ONN(\"this code shouldn't succeed\", ne_ssl_cert_cmp(NULL, NULL) == 0);\n    ONN(\"this code shouldn't run\", ne_ssl_clicert_fromuri(\"Makefile\", 0) != NULL);\n\n    ctx = ne_ssl_context_create(NE_SSL_CTX_CLIENT);\n    if (ctx) {\n        enum ne_ssl_protocol unspec = NE_SSL_PROTO_UNSPEC;\n        int out;\n        \n        (void) ne_ssl_context_trustcert(ctx, cert);\n        (void) ne_ssl_context_trustdefca(ctx);\n        ONN(\"this code shouldn't run\", ne_ssl_context_keypair(ctx, NULL, NULL) == 0);\n        (void) ne_ssl_context_set_clicert(ctx, NULL);\n        (void) ne_ssl_context_set_ccprovide(ctx, NULL, NULL);\n        ONN(\"this code shouldn't run\", ne_ssl_context_set_versions(ctx, unspec, unspec) == 0);\n        ONN(\"this code shouldn't run\", ne_ssl_context_set_verify(ctx, 0, NULL, NULL) == 0);\n        ONN(\"this code shouldn't run\", ne_ssl_context_get_flag(ctx, 0) == 0);\n        (void) ne_ssl_context_set_flag(ctx, 0, 0);\n        ONN(\"this code shouldn't run\", ne_ssl_check_certificate(ctx, NULL, \n                                                                NULL, NULL, cert,\n                                                                0, &out));\n        (void) ne_ssl_context_destroy(ctx);\n    }\n\n    ONN(\"certificate load succeeded\", cert != NULL);\n    ne_ssl_cert_free(cert);\n\n    cc = ne_ssl_clicert_read(\"Makefile\");\n    if (cc) {\n        const char *name;\n        /* dead branch as above. */\n        cert = (void *)ne_ssl_clicert_owner(cc);\n        ONN(\"this code shouldn't run\", cert != NULL);\n        name = ne_ssl_clicert_name(cc);\n        ONN(\"this code shouldn't run\", name != NULL);\n        ONN(\"this code shouldn't run\", ne_ssl_clicert_decrypt(cc, \"fubar\"));\n        ne_ssl_set_clicert(sess, ne_ssl_clicert_copy(cc));\n    }\n\n    ONN(\"client certificate load succeeded\", cc != NULL);\n    ne_ssl_clicert_free(cc);\n\n    ne_ssl_trust_default_ca(sess);\n\n    ne_session_destroy(sess);\n    return OK;\n}\n#endif\n\n#ifndef HAVE_PAKCHOIS\nstatic int stub_pkcs11(void)\n{\n    ne_session *sess = ne_session_create(\"https\", \"localhost\", 1234);\n    ne_ssl_pkcs11_provider *prov;\n\n    if (ne_ssl_pkcs11_provider_init(&prov, \"neon-test-failure-case\") == NE_PK11_OK) {\n        ONN(\"this code shouldn't run\", prov != NULL);\n        ne_ssl_pkcs11_provider_pin(prov, NULL, NULL); /* noop */\n        ne_ssl_set_pkcs11_provider(sess, prov); /* noop */\n        ne_ssl_pkcs11_provider_destroy(prov);\n    }\n\n    ONN(\"must return NOTIMPL\",\n        ne_ssl_pkcs11_provider_init(&prov, \"neon-test-failure-case-2\") != NE_PK11_NOTIMPL);\n\n    if (ne_ssl_pkcs11_nss_provider_init(&prov, \"neon-test-failure-case\",\n                                        \"neon-test\", NULL, NULL, NULL) == NE_PK11_OK) {\n        ONN(\"this code shouldn't run\", prov != NULL);\n        ne_ssl_pkcs11_provider_destroy(prov);\n    }\n\n    ne_session_destroy(sess);\n\n    return OK;\n}\n#endif\n\n#ifdef NO_TESTS\nstatic int null_test(void) { return OK; }\n#endif\n\nne_test tests[] = {\n#ifndef NE_HAVE_ZLIB\n    T(stub_decompress),\n#endif\n#ifndef NE_HAVE_SSL\n    T(stub_ssl),\n#endif\n#ifndef HAVE_PAKCHOIS\n    T(stub_pkcs11),\n#endif\n/* to prevent failure when SSL and zlib are supported. */\n#ifdef NO_TESTS\n    T(null_test),\n#endif\n    T(NULL) \n};\n\n"
  },
  {
    "path": "test/symvers.txt",
    "content": "ne_207_create\nne_207_destroy\nne_207_get_current_propstat\nne_207_get_current_response\nne_207_set_flags@@NEON_0_31\nne_207_set_propstat_handlers\nne_207_set_response_handlers\nne_accept_207\nne_accept_2xx\nne_accept_always\nne_acl3744_set@@NEON_0_29\nne_acl_set\nne_add_auth@@NEON_0_32\nne_add_depth_header\nne_add_interim_handler@@NEON_0_33\nne_add_proxy_auth\nne_add_request_header\nne_add_response_body_reader\nne_add_server_auth\nne_addr_canonical@@NEON_0_30\nne_addr_destroy\nne_addr_error\nne_addr_first\nne_addr_next\nne_addr_resolve\nne_addr_result\nne_ascii_to_md5\nne_asctime_parse\nne_base64\nne_begin_request\nne_buffer_altered\nne_buffer_append\nne_buffer_clear\nne_buffer_concat\nne_buffer_create\nne_buffer_destroy\nne_buffer_finish\nne_buffer_grow\nne_buffer_ncreate\nne_buffer_qappend@@NEON_0_29\nne_buffer_snprintf\nne_buffer_zappend\nne_calloc\nne_close_connection\nne_concat\nne_copy\nne_debug\nne_debug_init\nne_debug_mask\nne_debug_stream\nne_decompress_destroy\nne_decompress_reader\nne_delete\nne_discard_response\nne_end_request\nne_fill_proxy_uri\nne_fill_server_uri\nne_forget_auth\nne_get\nne_get_content_type\nne_get_error\nne_get_range\nne_get_request_flag\nne_get_request_private\nne_get_request_target@@NEON_0_34\nne_get_response_header\nne_get_response_location@@NEON_0_34\nne_get_response_retry_after@@NEON_0_35\nne_get_response_trailer@@NEON_0_37\nne_get_scheme\nne_get_server_hostport\nne_get_session\nne_get_session_flag\nne_get_session_private\nne_get_status\nne_getbuf@@NEON_0_36\nne_getmodtime\nne_has_support\nne_hook_close_conn\nne_hook_create_request\nne_hook_destroy_request\nne_hook_destroy_session\nne_hook_post_headers\nne_hook_post_send\nne_hook_pre_send\nne_httpdate_parse\nne_i18n_init\nne_iaddr_cmp\nne_iaddr_free\nne_iaddr_get_scope@@NEON_0_34\nne_iaddr_make\nne_iaddr_parse\nne_iaddr_print\nne_iaddr_put@@NEON_0_37\nne_iaddr_raw@@NEON_0_29\nne_iaddr_reverse\nne_iaddr_set_scope@@NEON_0_34\nne_iaddr_typeof\nne_iso8601_parse\nne_lock\nne_lock_copy\nne_lock_create\nne_lock_destroy\nne_lock_discover\nne_lock_free\nne_lock_refresh\nne_lock_using_parent\nne_lock_using_resource\nne_lockstore_add\nne_lockstore_create\nne_lockstore_destroy\nne_lockstore_findbyuri\nne_lockstore_first\nne_lockstore_next\nne_lockstore_register\nne_lockstore_remove\nne_malloc\nne_md5_create_ctx\nne_md5_destroy_ctx\nne_md5_dup_ctx\nne_md5_finish_ascii\nne_md5_finish_ctx\nne_md5_process_block\nne_md5_process_bytes\nne_md5_read_ctx\nne_md5_reset_ctx\nne_md5_stream\nne_md5_to_ascii\nne_mkcol\nne_mknonce@@NEON_0_37\nne_move\nne_oom_callback\nne_options\nne_options2\nne_parse_statusline\nne_path_childof\nne_path_compare\nne_path_escape\nne_path_escapef@@NEON_0_31\nne_path_has_trailing_slash\nne_path_parent\nne_path_unescape\nne_post\nne_print_request_header\nne_propfind_allprop\nne_propfind_create\nne_propfind_current_private\nne_propfind_destroy\nne_propfind_get_parser\nne_propfind_get_request\nne_propfind_named\nne_propfind_set_private\nne_propnames\nne_proppatch\nne_propset_iterate\nne_propset_lang\nne_propset_private\nne_propset_status\nne_propset_value\nne_put\nne_putbuf@@NEON_0_33\nne_qtoken\nne_read_response_block\nne_read_response_to_buffer@@NEON_0_36\nne_read_response_to_fd\nne_realloc\nne_redirect_location\nne_redirect_register\nne_request_create\nne_request_destroy\nne_request_dispatch\nne_response_header_iterate\nne_response_trailer_iterate@@NEON_0_37\nne_rfc1036_parse\nne_rfc1123_date\nne_rfc1123_parse\nne_session_create\nne_session_destroy\nne_session_proxy\nne_session_socks_proxy@@NEON_0_29\nne_session_system_proxy@@NEON_0_29\nne_set_addrlist\nne_set_addrlist2@@NEON_0_30\nne_set_connect_timeout\nne_set_error\nne_set_localaddr\nne_set_notifier\nne_set_progress\nne_set_proxy_auth\nne_set_read_timeout\nne_set_request_body_buffer\nne_set_request_body_fd\nne_set_request_body_provider\nne_set_request_flag\nne_set_request_private\nne_set_server_auth\nne_set_session_flag\nne_set_session_private\nne_set_useragent\nne_shave\nne_simple_propfind\nne_simple_request\nne_snprintf\nne_sock_accept\nne_sock_accept_ssl\nne_sock_block\nne_sock_cipher\nne_sock_close\nne_sock_connect\nne_sock_connect_ssl\nne_sock_connect_timeout\nne_sock_create\nne_sock_error\nne_sock_exit\nne_sock_fd\nne_sock_fullread\nne_sock_fullwrite\nne_sock_fullwritev@@NEON_0_29\nne_sock_getcert@@NEON_0_37\nne_sock_getproto@@NEON_0_34\nne_sock_handshake@@NEON_0_37\nne_sock_init\nne_sock_peek\nne_sock_peer\nne_sock_prebind\nne_sock_proxy@@NEON_0_29\nne_sock_read\nne_sock_read_timeout\nne_sock_readline\nne_sock_sessid\nne_sock_set_error@@NEON_0_29\nne_sock_shutdown@@NEON_0_32\nne_ssl_cert_cmp\nne_ssl_cert_digest\nne_ssl_cert_export\nne_ssl_cert_free\nne_ssl_cert_hdigest@@NEON_0_32\nne_ssl_cert_identity\nne_ssl_cert_import\nne_ssl_cert_issuer\nne_ssl_cert_read\nne_ssl_cert_signedby\nne_ssl_cert_subject\nne_ssl_cert_validity\nne_ssl_cert_validity_time\nne_ssl_cert_write\nne_ssl_check_certificate@@NEON_0_37\nne_ssl_clicert_copy@@NEON_0_37\nne_ssl_clicert_decrypt\nne_ssl_clicert_encrypted\nne_ssl_clicert_free\nne_ssl_clicert_fromuri@@NEON_0_35\nne_ssl_clicert_import@@NEON_0_30\nne_ssl_clicert_name\nne_ssl_clicert_owner\nne_ssl_clicert_read\nne_ssl_context_create\nne_ssl_context_destroy\nne_ssl_context_get_flag@@NEON_0_30\nne_ssl_context_keypair\nne_ssl_context_set_ccprovide@@NEON_0_37\nne_ssl_context_set_clicert@@NEON_0_37\nne_ssl_context_set_flag\nne_ssl_context_set_verify\nne_ssl_context_set_versions@@NEON_0_34\nne_ssl_context_trustcert\nne_ssl_context_trustdefca@@NEON_0_37\nne_ssl_dname_cmp\nne_ssl_pkcs11_nss_provider_init\nne_ssl_pkcs11_provider_destroy\nne_ssl_pkcs11_provider_init\nne_ssl_pkcs11_provider_pin\nne_ssl_proto_name@@NEON_0_34\nne_ssl_provide_clicert\nne_ssl_readable_dname\nne_ssl_set_clicert\nne_ssl_set_pkcs11_provider\nne_ssl_set_protovers@@NEON_0_34\nne_ssl_set_verify\nne_ssl_trust_cert\nne_ssl_trust_default_ca\nne_strcasecmp\nne_strclean\nne_strdup\nne_strerror\nne_strhash@@NEON_0_32\nne_strhextoul@@NEON_0_35\nne_strlower@@NEON_0_37\nne_strncasecmp\nne_strndup\nne_strnqdup@@NEON_0_29\nne_strparam@@NEON_0_32\nne_strupper@@NEON_0_37\nne_token\nne_tolower_array\nne_unbase64\nne_unhook_close_conn\nne_unhook_create_request\nne_unhook_destroy_request\nne_unhook_destroy_session\nne_unhook_post_headers\nne_unhook_post_send\nne_unhook_pre_send\nne_unlock\nne_uri_cmp\nne_uri_copy\nne_uri_defaultport\nne_uri_free\nne_uri_parse\nne_uri_resolve\nne_uri_unparse\nne_version_library@@NEON_0_37\nne_version_match\nne_version_pre_http11\nne_version_string\nne_vsnprintf\nne_vstrhash@@NEON_0_32\nne_xml_create\nne_xml_currentline\nne_xml_destroy\nne_xml_dispatch_request\nne_xml_dispatchif_request@@NEON_0_36\nne_xml_doc_encoding\nne_xml_failed\nne_xml_get_attr\nne_xml_get_error\nne_xml_mapid\nne_xml_parse\nne_xml_parse_response\nne_xml_parse_v\nne_xml_push_handler\nne_xml_resolve_nspace\nne_xml_set_encoding@@NEON_0_36\nne_xml_set_error\n"
  },
  {
    "path": "test/twooh7.c",
    "content": "/* \n   Test cases for the ne_207.h interface.\n   Copyright (C) 2023, Joe Orton <joe@manyfish.co.uk>\n\n   This program is free software; you can redistribute it and/or modify\n   it under the terms of the GNU General Public License as published by\n   the Free Software Foundation; either version 2 of the License, or\n   (at your option) any later version.\n  \n   This program is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU General Public License for more details.\n  \n   You should have received a copy of the GNU General Public License\n   along with this program; if not, write to the Free Software\n   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\n*/\n\n#include \"config.h\"\n\n#include <sys/types.h>\n\n#ifdef HAVE_STDLIB_H\n#include <stdlib.h>\n#endif\n#ifdef HAVE_UNISTD_H\n#include <unistd.h>\n#endif\n\n#include \"ne_207.h\"\n\n#include \"tests.h\"\n#include \"utils.h\"\n\n#define PFX \"<?xml version='1.0' encoding='utf-8'?>\\r\\n\"\n\n#define RESP(status, rdesc) \"<d:response>\"                              \\\n    \"<d:href>http://localhost/container/resource3</d:href>\"       \\\n    status rdesc                                                        \\\n    \"</d:response>\"\n\n#define MS_207_1(status, rdesc) PFX               \\\n    \"<d:multistatus xmlns:d=\\\"DAV:\\\">\"          \\\n    RESP(status, rdesc)                         \\\n    \"</d:multistatus>\"\n\n#define MS_207_2(s1, rd1, s2, rd2) PFX          \\\n    \"<d:multistatus xmlns:d=\\\"DAV:\\\">\"          \\\n    RESP(s1, rd1)                               \\\n    RESP(s2, rd2)                             \\\n    \"</d:multistatus>\"\n\nstatic int simples(void)\n{\n    static const struct {\n        int status;\n        const char *ctype;\n        const char *body;\n        const char *expect; /* NULL for success cases. */\n    } ts[] = {\n        { 207, \"application/xml\",\n          MS_207_1(\"<d:status>HTTP/1.1 423 Locked</d:status>\", \"\"),\n          \"423 Locked\" },\n        { 207, \"application/xml\",\n          MS_207_1(\"<d:status>HTTP/1.1 423 Locked</d:status>\",\n                   \"<d:responsedescription>The thing was locked</d:responsedescription>\"),\n          \"The thing was\" },\n#if 0\n         { 207, \"application/xml\",\n          MS_207_1(\"<d:status>HTTP/1.1 423 Locked</d:status>\",\n                   \"<d:error><d:lock-token-submitted/></d:error>\"),\n          \"Resource locked\" },\n#endif\n        { 207, \"application/xml\",\n          MS_207_2(\"<d:status>HTTP/1.1 423 Locked</d:status>\",\n                   \"<d:responsedescription>The thing was locked</d:responsedescription>\",\n                   \"<d:status>HTTP/1.1 404 Gone</d:status>\",\n                 \"<d:responsedescription>No such thingy</d:responsedescription>\"),\n          \"such thingy\" },\n        /* Test that 201 responses are NOT parsed. */\n        { 201, \"application/xml\", \"<malformed-xml>\", NULL },\n        /* Test that non-2xx response is also an error. */\n        { 404, \"application/xml\", \"<malformed-xml>\", \"404\" }\n    };\n    unsigned n;\n\n    for (n = 0; n < sizeof(ts)/sizeof(ts[0]); n++) {\n        char resp[1024];\n        ne_session *sess;\n        ne_request *req;\n        char *err;\n        int ret;\n\n        ne_snprintf(resp, sizeof resp,\n                    \"HTTP/1.1 %d OK\\r\\n\"\n                    \"Content-Type: %s\\r\\n\"\n                    \"Connection: close\\r\\n\" \"\\r\\n\"\n                    \"%s\", ts[n].status, ts[n].ctype, ts[n].body);\n\n        CALL(make_session(&sess, single_serve_string, resp));\n\n        req = ne_request_create(sess, \"SIMPLE\", \"/\");\n\n        ret = ne_simple_request(sess, req);\n\n        if (ts[n].expect) {\n            ONN(\"ne_simple_request didn't fail\", ret == NE_OK);\n\n            err = ne_strclean(ne_strdup(ne_get_error(sess)));\n            ONV(strcmp(err, ne_get_error(sess)),\n                (\"error string wasn't cleaned: %s\", ne_get_error(sess)));\n            NE_DEBUG(NE_DBG_HTTP, \"test: got error string: %s\\n\", err);\n            ne_free(err);\n\n            ONV(strstr(ne_get_error(sess), ts[n].expect) == NULL,\n                (\"error string didn't match: '%s' - expected '%s'\",\n                 ne_get_error(sess), ts[n].expect));\n        }\n        else {\n            ONREQ(ret);\n        }\n\n        CALL(destroy_and_wait(sess));\n    }\n\n    return OK;\n}\n\nstatic int pstat_count;\n\n/* tos_*: set of 207 callbacks which serialize the data back into a\n * text stream, which can be easily checked for correctness. */\nstatic void *tos_startresp(void *buf, const ne_uri *uri)\n{\n    ne_buffer_concat(buf, \"start-resp[\", uri->path, \"];\", NULL);\n    pstat_count = 0;\n    return ne_strdup(uri->path);\n}\n\nstatic void tos_status_descr(ne_buffer *buf, const ne_status *status,\n                             const char *description)\n{\n    if (status) {\n        char s[50];\n        ne_snprintf(s, sizeof s, \"-status={%d %s}\", status->code,\n                    status->reason_phrase);\n        ne_buffer_zappend(buf, s);\n    }\n    if (description)\n        ne_buffer_concat(buf, \"-descr={\", description, \"}\", NULL);\n}\n\nstatic void tos_endresp(void *buf, void *response,\n                        const ne_status *status, const char *description)\n{\n    char *href = response;\n    ne_buffer_concat(buf, \"end-resp[\", href, \"]\", NULL);\n    ne_free(href);\n    tos_status_descr(buf, status, description);\n    ne_buffer_zappend(buf, \";\");\n}\n\nstatic void *tos_startpstat(void *buf, void *resphref)\n{\n    char num[20], *href;\n    sprintf(num, \"-%d\", ++pstat_count);\n    href = ne_concat(resphref, num, NULL);\n    ne_buffer_concat(buf, \"start-pstat[\", href, \"];\", NULL);\n    return href;\n}\n\nstatic void tos_endpstat(void *buf, void *href,\n                         const ne_status *status, const char *description)\n{\n    ne_buffer_concat(buf, \"end-pstat[\", href, \"]\", NULL);\n    tos_status_descr(buf, status, description);\n    ne_buffer_zappend(buf, \";\");\n    ne_free(href);\n}\n\nstruct propctx {\n    ne_207_parser *p207;\n    ne_buffer *buf;\n};\n\n#define STATE_myprop (NE_207_STATE_TOP)\n\nstatic int tos_startprop(void *userdata, int parent,\n                         const char *nspace, const char *name,\n                         const char **atts)\n{\n    if (parent == NE_207_STATE_PROP\n        && strcmp(nspace, \"DAV:\") == 0\n        && (strcmp(name, \"propone\") == 0 || strcmp(name, \"proptwo\") == 0)) {\n        /* Handle this! */\n        struct propctx *ctx = userdata;\n        char *resphref = ne_207_get_current_response(ctx->p207);\n        char *pstathref = ne_207_get_current_propstat(ctx->p207);\n        \n        ne_buffer_concat(ctx->buf, \"start-prop[\", resphref, \",\", pstathref,\n                         \",\", name, \"];\", NULL);\n\n        return STATE_myprop;\n    }\n    else {\n        return NE_XML_DECLINE;\n    }\n}\n\nstatic int tos_cdata(void *userdata, int state,\n                     const char *cdata, size_t len)\n{\n    struct propctx *ctx = userdata;\n\n    ne_buffer_zappend(ctx->buf, \"cdata-prop[\");\n    ne_buffer_append(ctx->buf, cdata, len);\n    ne_buffer_zappend(ctx->buf, \"];\");\n    return 0;\n}\n\nstatic int tos_endprop(void *userdata, int state,\n                       const char *nspace, const char *name)\n{\n    struct propctx *ctx = userdata;\n\n    ne_buffer_concat(ctx->buf, \"end-prop[\", name, \"];\", NULL);\n    return 0;\n}\n\nstatic int run_207_response(const char *resp, const char *expected)\n{\n    ne_buffer *buf = ne_buffer_create();\n    ne_session *sess;\n    ne_xml_parser *p = ne_xml_create();\n    ne_207_parser *p207;\n    ne_request *req;\n    ne_uri base = {0};\n    struct propctx ctx;\n\n    CALL(session_server(&sess, single_serve_string, (char *)resp));\n    req = ne_request_create(sess, \"PROPFIND\", \"/foo\");\n    ne_fill_server_uri(sess, &base);\n    base.path = ne_strdup(\"/foo\");\n    p207 = ne_207_create(p, &base, buf);\n    ne_uri_free(&base);\n\n    ne_add_response_body_reader(req, ne_accept_207, ne_xml_parse_v, p);\n\n    ne_207_set_response_handlers(p207, tos_startresp, tos_endresp);\n    ne_207_set_propstat_handlers(p207, tos_startpstat, tos_endpstat);\n\n    ctx.buf = buf;\n    ctx.p207 = p207;\n    ne_xml_push_handler(p, tos_startprop, tos_cdata, tos_endprop, &ctx);\n\n    ONREQ(ne_request_dispatch(req));\n\n    CALL(await_server());\n\n    ONV(ne_xml_failed(p),\n        (\"parse error in response body: %s\", ne_xml_get_error(p)));\n\n    ONV(strcmp(buf->data, expected),\n        (\"comparison failed.\\n\"\n         \"expected string: `%s'\\n\"\n         \"got string:      `%s'\", expected, buf->data));\n\n    ne_buffer_destroy(buf);\n    ne_207_destroy(p207);\n    ne_xml_destroy(p);\n    ne_request_destroy(req);\n    ne_session_destroy(sess);\n    return OK;\n}\n\n/* Tests for the 207 interface: send a 207 response body, compare the\n * re-serialized string returned with that expected. */\nstatic int two_oh_seven(void)\n{\n    static const char *ts[][2] = {\n        { MULTI_207(RESP_207(\"/foo\", \"\")),\n          \"start-resp[/foo];end-resp[/foo];\" },\n\n        /* test for response status handling */\n        { MULTI_207(RESP_207(\"/bar\", STAT_207(\"200 OK\"))), \n          \"start-resp[/bar];end-resp[/bar]-status={200 OK};\" },\n\n        /* test that empty description == NULL description argument */\n        { MULTI_207(RESP_207(\"/bar\", STAT_207(\"200 OK\") DESCR_207(\"\"))), \n          \"start-resp[/bar];end-resp[/bar]-status={200 OK};\" },\n\n        /* test multiple responses */\n        { MULTI_207(RESP_207(\"/hello/world\", STAT_207(\"200 OK\"))\n                    RESP_207(\"/foo/bar\", STAT_207(\"599 French Fries\"))),\n          \"start-resp[/hello/world];end-resp[/hello/world]-status={200 OK};\"\n          \"start-resp[/foo/bar];end-resp[/foo/bar]\"\n          \"-status={599 French Fries};\"\n        },\n\n        /* test multiple propstats in multiple responses */\n        { MULTI_207(RESP_207(\"/al/pha\", \n                             PSTAT_207(STAT_207(\"321 Une\"))\n                             PSTAT_207(STAT_207(\"432 Deux\"))\n                             PSTAT_207(STAT_207(\"543 Trois\")))\n                    RESP_207(\"/be/ta\",\n                             PSTAT_207(STAT_207(\"587 Quatre\"))\n                             PSTAT_207(STAT_207(\"578 Cinq\")))),\n          \"start-resp[/al/pha];\"\n          \"start-pstat[/al/pha-1];end-pstat[/al/pha-1]-status={321 Une};\"\n          \"start-pstat[/al/pha-2];end-pstat[/al/pha-2]-status={432 Deux};\"\n          \"start-pstat[/al/pha-3];end-pstat[/al/pha-3]-status={543 Trois};\"\n          \"end-resp[/al/pha];\"\n          \"start-resp[/be/ta];\"\n          \"start-pstat[/be/ta-1];end-pstat[/be/ta-1]-status={587 Quatre};\"\n          \"start-pstat[/be/ta-2];end-pstat[/be/ta-2]-status={578 Cinq};\"\n          \"end-resp[/be/ta];\"\n        },\n\n        /* test that incomplete responses are completely ignored. */\n        { MULTI_207(\"<D:response/>\"\n                    RESP_207(\"/\", STAT_207(\"123 Hoorah\"))\n                    \"<D:response/>\"\n                    \"<D:response><D:propstat>hello</D:propstat></D:response>\"\n                    \"<D:response><D:href/></D:response>\"\n                    RESP_207(\"/bar\", STAT_207(\"200 OK\"))),\n          \"start-resp[/];end-resp[/]-status={123 Hoorah};\"\n          \"start-resp[/bar];end-resp[/bar]-status={200 OK};\" },\n\n        /* tests for propstat status */\n        { MULTI_207(RESP_207(\"/pstat\",\n                            PSTAT_207(\"<D:prop/>\" STAT_207(\"466 Doomed\")))),\n          \"start-resp[/pstat];start-pstat[/pstat-1];\"\n          \"end-pstat[/pstat-1]-status={466 Doomed};end-resp[/pstat];\" },\n\n        { MULTI_207(RESP_207(\"/pstat\", PSTAT_207(\"<D:status/>\"))),\n          \"start-resp[/pstat];start-pstat[/pstat-1];\"\n          \"end-pstat[/pstat-1];end-resp[/pstat];\" },\n\n        /* tests for responsedescription handling */\n        { MULTI_207(RESP_207(\"/bar\", STAT_207(\"200 OK\") DESCR_207(DESCR_REM))), \n          \"start-resp[/bar];end-resp[/bar]-status={200 OK}\"\n          \"-descr={\" DESCR_REM \"};\" },\n\n        { MULTI_207(RESP_207(\"/bar\",\n                             PSTAT_207(STAT_207(\"456 Too Hungry\")\n                                       DESCR_207(\"Not enough food available\"))\n                             STAT_207(\"200 OK\") DESCR_207(\"Not \" DESCR_REM))), \n          \"start-resp[/bar];\"\n          \"start-pstat[/bar-1];end-pstat[/bar-1]-status={456 Too Hungry}\"\n          \"-descr={Not enough food available};\"\n          \"end-resp[/bar]-status={200 OK}-descr={Not \" DESCR_REM \"};\" },\n\n        /* intermingle some random elements and cdata to make sure\n         * they are ignored. */\n        { MULTI_207(\"<D:fish-food/>blargl\" \n                    RESP_207(\"/b<ping-pong/>ar\", \"<D:sausages/>\"\n                             PSTAT_207(\"<D:hello-mum/>blergl\") \n                             STAT_207(\"200 OK\") \"<D:blah>foop</D:blah>\"\n                             DESCR_207(DESCR_REM) \"carroon\") \n                    \"carapi\"), \n          \"start-resp[/bar];start-pstat[/bar-1];end-pstat[/bar-1];\"\n          \"end-resp[/bar]-status={200 OK}-descr={\" DESCR_REM \"};\" },\n\n        /* test for properties within a 207. */\n        { MULTI_207(RESP_207(\"/alpha\",\n                             PSTAT_207(PROPS_207(\n                                           APROP_207(\"propone\", \"hello\")\n                                           APROP_207(\"proptwo\", \"foobar\"))\n                                       STAT_207(\"200 OK\")))),\n          \"start-resp[/alpha];start-pstat[/alpha-1];\"\n          \"start-prop[/alpha,/alpha-1,propone];cdata-prop[hello];\"\n          \"end-prop[propone];\"\n          \"start-prop[/alpha,/alpha-1,proptwo];cdata-prop[foobar];\"\n          \"end-prop[proptwo];\"\n          \"end-pstat[/alpha-1]-status={200 OK};end-resp[/alpha];\" },\n\n        /* test for whitespace around href, which should be\n         * ignored. */\n        { MULTI_207(RESP_207(\" /spaces \", STAT_207(\"200 OK\") DESCR_207(\"\"))),\n          \"start-resp[/spaces];end-resp[/spaces]-status={200 OK};\" },\n\n        /* test for whitespace around href, which should be\n         * ignored. */\n        { MULTI_207(RESP_207(\" /spaces \", STAT_207(\"200 OK\\n\") DESCR_207(\"\"))),\n          \"start-resp[/spaces];end-resp[/spaces]-status={200 OK};\" },\n\n        /* test for omitted reason-phrase in status-line, which is\n         * valid, per https://github.com/notroj/neon/issues/188 */\n        { MULTI_207(RESP_207(\"/bar\", STAT_207(\"200 \") DESCR_207(\"\"))),\n          \"start-resp[/bar];end-resp[/bar]-status={200 };\" }\n    };\n    unsigned n;\n\n    for (n = 0; n < sizeof(ts)/sizeof(ts[0]); n++)\n        CALL(run_207_response(ts[n][0], ts[n][1]));\n\n    return OK;\n}\n\nne_test tests[] = {\n    T(simples),\n    T(two_oh_seven),\n    T(NULL)\n};\n\n"
  },
  {
    "path": "test/uri-tests.c",
    "content": "/* \n   URI handling tests\n   Copyright (C) 2001-2006, Joe Orton <joe@manyfish.co.uk>\n\n   This program is free software; you can redistribute it and/or modify\n   it under the terms of the GNU General Public License as published by\n   the Free Software Foundation; either version 2 of the License, or\n   (at your option) any later version.\n  \n   This program is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU General Public License for more details.\n  \n   You should have received a copy of the GNU General Public License\n   along with this program; if not, write to the Free Software\n   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\n*/\n\n#include \"config.h\"\n\n#ifdef HAVE_STDLIB_H\n#include <stdlib.h>\n#endif\n#ifdef HAVE_STRING_H\n#include <string.h>\n#endif\n\n#include \"ne_uri.h\"\n#include \"ne_alloc.h\"\n\n#include \"tests.h\"\n\nstatic int simple(void)\n{\n    ne_uri p = {0};\n    ON(ne_uri_parse(\"http://www.webdav.org/foo\", &p));\n    ON(strcmp(p.host, \"www.webdav.org\"));\n    ON(strcmp(p.path, \"/foo\"));\n    ON(strcmp(p.scheme, \"http\"));\n    ON(p.port);\n    ON(p.userinfo != NULL);\n    ne_uri_free(&p);\n    return 0;\n}\n\nstatic int simple_ssl(void)\n{\n    ne_uri p = {0};\n    ON(ne_uri_parse(\"https://webdav.org/\", &p));\n    ON(strcmp(p.scheme, \"https\"));\n    ON(p.port);\n    ne_uri_free(&p);\n    return OK;\n}\n\nstatic int no_path(void)\n{\n    ne_uri p = {0};\n    ON(ne_uri_parse(\"https://webdav.org\", &p));\n    ON(strcmp(p.path, \"/\"));\n    ne_uri_free(&p);\n    return OK;\n}\n\nstatic int escapes(void)\n{\n    static const struct {\n        const char *plain, *escaped;\n        unsigned int flags;\n    } paths[] = {\n        { \"/foo%\", \"/foo%25\", 0 },\n        { \"/foo bar\", \"/foo%20bar\", 0, },\n        { \"/foo_bar\", \"/foo_bar\", 0 },\n        { \"/foobar\", \"/foobar\", 0 },\n        { \"/a\\xb9\\xb2\\xb3\\xbc\\xbd/\", \"/a%b9%b2%b3%bc%bd/\", 0 },\n        { \"/foo%20\\xb9\\xb2\\xb3\\xbc\\xbd/\", \"/foo%20%b9%b2%b3%bc%bd/\", NE_PATH_NONURI },\n        { \"/foo bar/\", \"/foo%20bar/\", NE_PATH_NONURI },\n        { \"/foo:bar\", \"/foo:bar\", NE_PATH_NONPC },\n        { \"/a#b:2\", \"/a%23b:2\", NE_PATH_NONPC },\n        { \"/a#b:2\", \"/a%23b:2\", 0 },\n        { \"/a?b:c$d\", \"/a%3fb:c$d\", NE_PATH_NONPC },\n        { NULL, NULL}\n    };\n    size_t n;\n\n    for (n = 0; paths[n].plain; n++) {\n        char *esc;\n\n        if (paths[n].flags)\n            esc = ne_path_escapef(paths[n].plain, paths[n].flags);\n        else\n            esc = ne_path_escape(paths[n].plain);\n\n        ONCMP(paths[n].escaped, esc, paths[n].plain, \"escaped form\");\n\n        if (!paths[n].flags) {\n            char *un = ne_path_unescape(esc);\n\n            ONCMP(paths[n].plain, un, paths[n].plain, \"unescape\");\n            ne_free(un);\n        }\n\n        ne_free(esc);\n    }\n\n    ONN(\"unescape accepted invalid URI\", \n        ne_path_unescape(\"/foo%zzbar\") != NULL);\n    ONN(\"unescape accepted invalid URI\", \n        ne_path_unescape(\"/foo%1zbar\") != NULL);\n\n    return OK;\n}    \n\nstatic int parents(void)\n{\n    static const struct {\n\tconst char *path, *parent;\n    } ps[] = {\n\t{ \"/a/b/c\", \"/a/b/\" },\n\t{ \"/a/b/c/\", \"/a/b/\" },\n\t{ \"/alpha/beta\", \"/alpha/\" },\n\t{ \"/foo\", \"/\" },\n\t{ \"norman\", NULL },\n\t{ \"/\", NULL },\n\t{ \"\", NULL },\n\t{ NULL, NULL }\n    };\n    int n;\n    \n    for (n = 0; ps[n].path != NULL; n++) {\n\tchar *p = ne_path_parent(ps[n].path);\n\tif (ps[n].parent == NULL) {\n\t    ONV(p != NULL, (\"parent of `%s' was `%s' not NULL\", \n\t\t\t    ps[n].path, p));\n\t} else {\n\t    ONV(p == NULL, (\"parent of `%s' was NULL\", ps[n].path));\n\t    ONV(strcmp(p, ps[n].parent),\n\t\t(\"parent of `%s' was `%s' not `%s'\",\n\t\t ps[n].path, p, ps[n].parent));\n\t    ne_free(p);\n\t}\n    }\n\n    return OK;\n}\n\nstatic int compares(void)\n{\n    const char *alpha = \"/alpha\";\n\n    ON(ne_path_compare(\"/a\", \"/a/\") != 0);\n    ON(ne_path_compare(\"/a/\", \"/a\") != 0);\n    ON(ne_path_compare(\"/ab\", \"/a/\") == 0);\n    ON(ne_path_compare(\"/a/\", \"/ab\") == 0);\n    ON(ne_path_compare(\"/a/\", \"/a/\") != 0);\n    ON(ne_path_compare(\"/alpha/\", \"/beta/\") == 0);\n    ON(ne_path_compare(\"/alpha\", \"/b\") == 0);\n    ON(ne_path_compare(\"/alpha/\", \"/alphash\") == 0);\n    ON(ne_path_compare(\"/fish/\", \"/food\") == 0);\n    ON(ne_path_compare(alpha, alpha) != 0);\n    ON(ne_path_compare(\"/a/b/c/d\", \"/a/b/c/\") == 0);\n    return OK;\n}\n\nstatic int cmp(void)\n{\n    static const struct {\n        const char *left, *right;\n    } eq[] = {\n        { \"http://example.com/alpha\", \"http://example.com/alpha\" },\n        { \"//example.com/alpha\", \"//example.com/alpha\" },\n        { \"http://example.com/alpha#foo\", \"http://example.com/alpha#foo\" },\n        { \"http://example.com/alpha?bar\", \"http://example.com/alpha?bar\" },\n        { \"http://jim@example.com/alpha\", \"http://jim@example.com/alpha\" },\n        { \"HTTP://example.com/alpha\", \"http://example.com/alpha\" },\n        { \"http://example.com/\", \"http://example.com\" },\n        { \"http://Example.Com/\", \"http://example.com\" },\n        { NULL, NULL}\n    }, diff[] = {\n        { \"http://example.com/alpha\", \"http://example.com/beta\" },\n        { \"http://example.com/alpha\", \"https://example.com/alpha\" },\n        { \"http://example.com/alpha\", \"http://www.example.com/alpha\" },\n        { \"http://example.com:443/alpha\", \"http://example.com:8080/alpha\" },\n        { \"http://example.com/alpha\", \"http://jim@example.com/alpha\" },\n        { \"http://bob@example.com/alpha\", \"http://jim@example.com/alpha\" },\n        { \"http://example.com/alpha\", \"http://example.com/alpha?fish\" },\n        { \"http://example.com/alpha?fish\", \"http://example.com/alpha?food\" },\n        { \"http://example.com/alpha\", \"http://example.com/alpha#foo\" },\n        { \"http://example.com/alpha#bar\", \"http://example.com/alpha#foo\" },\n        { \"http://example.com/alpha\", \"//example.com/alpha\" },\n        { \"http://example.com/alpha\", \"///alpha\" },\n        { NULL, NULL}\n    };\n    size_t n;\n\n    for (n = 0; eq[n].left; n++) {\n        ne_uri alpha, beta;\n        int r1, r2;\n\n        ONV(ne_uri_parse(eq[n].left, &alpha),\n            (\"could not parse left URI '%s'\", eq[n].left));\n\n        ONV(ne_uri_parse(eq[n].right, &beta),\n            (\"could not parse right URI '%s'\", eq[n].right));\n\n        r1 = ne_uri_cmp(&alpha, &beta); \n        r2 = ne_uri_cmp(&beta, &alpha); \n\n        ONV(r1 != 0,\n            (\"cmp('%s', '%s') = %d not zero\",\n             eq[n].left, eq[n].right, r1));\n\n        ONV(r2 != 0,\n            (\"cmp('%s', '%s') = %d not zero\",\n             eq[n].right, eq[n].left, r2));\n\n        ne_uri_free(&alpha);\n        ne_uri_free(&beta);\n    }\n\n    for (n = 0; diff[n].left; n++) {\n        ne_uri alpha, beta;\n        int r1, r2;\n\n        ONV(ne_uri_parse(diff[n].left, &alpha),\n            (\"could not parse left URI '%s'\", diff[n].left));\n\n        ONV(ne_uri_parse(diff[n].right, &beta),\n            (\"could not parse right URI '%s'\", diff[n].right));\n\n        r1 = ne_uri_cmp(&alpha, &beta); \n        r2 = ne_uri_cmp(&beta, &alpha); \n\n        ONV(r1 == 0,\n            (\"'%s' and '%s' did not compare as different\",\n             diff[n].left, diff[n].right));\n\n        ONV(((r1 > 0) != (r2 < 0) || (r1 < 0) != (r2 > 0)),\n            (\"'%s' and '%s' did not compare reflexively (%d vs %d)\",\n             diff[n].left, diff[n].right, r1, r2));\n\n        ne_uri_free(&alpha);\n        ne_uri_free(&beta);\n    }\n\n    return OK;\n}\n\nstatic int children(void)\n{\n    ON(ne_path_childof(\"/a\", \"/a/b\") == 0);\n    ON(ne_path_childof(\"/a/\", \"/a/b\") == 0);\n    ON(ne_path_childof(\"/aa/b/c\", \"/a/b/c/d/e\") != 0);\n    ON(ne_path_childof(\"////\", \"/a\") != 0);\n    return OK;\n}\n\nstatic int slash(void)\n{\n    ON(ne_path_has_trailing_slash(\"/a/\") == 0);\n    ON(ne_path_has_trailing_slash(\"/a\") != 0);\n    {\n\t/* check the uri == \"\" case. */\n\tchar *foo = \"/\";\n\tON(ne_path_has_trailing_slash(&foo[1]));\n    }\n    return OK;\n}\n\nstatic int default_port(void)\n{\n    ONN(\"default http: port incorrect\", ne_uri_defaultport(\"http\") != 80);\n    ONN(\"default https: port incorrect\", ne_uri_defaultport(\"https\") != 443);\n    ONN(\"unspecified scheme: port incorrect\", ne_uri_defaultport(\"ldap\") != 0);\n    return OK;\n}\n\nstatic int parse(void)\n{\n    static const struct test_uri {\n\tconst char *uri, *scheme, *host;\n\tunsigned int port;\n\tconst char *path, *userinfo, *query, *fragment;\n    } uritests[] = {\n        { \"http://webdav.org/norman\", \"http\", \"webdav.org\", 0, \"/norman\", NULL, NULL, NULL },\n        { \"http://webdav.org:/norman\", \"http\", \"webdav.org\", 0, \"/norman\", NULL, NULL, NULL },\n        { \"https://webdav.org/foo\", \"https\", \"webdav.org\", 0, \"/foo\", NULL, NULL, NULL },\n        { \"http://webdav.org:8080/bar\", \"http\", \"webdav.org\", 8080, \"/bar\", NULL, NULL, NULL },\n        { \"http://a/b\", \"http\", \"a\", 0, \"/b\", NULL, NULL, NULL },\n        { \"http://webdav.org/bar:fish\", \"http\", \"webdav.org\", 0, \"/bar:fish\", NULL, NULL, NULL },\n        { \"http://webdav.org\", \"http\", \"webdav.org\", 0, \"/\", NULL, NULL, NULL },\n        { \"http://webdav.org/fish@food\", \"http\", \"webdav.org\", 0, \"/fish@food\", NULL, NULL, NULL },\n\n        /* query/fragments */\n        { \"http://foo/bar?alpha\", \"http\", \"foo\", 0, \"/bar\", NULL, \"alpha\", NULL },\n        { \"http://foo/bar?alpha#beta\", \"http\", \"foo\", 0, \"/bar\", NULL, \"alpha\", \"beta\" },\n        { \"http://foo/bar#alpha?beta\", \"http\", \"foo\", 0, \"/bar\", NULL, NULL, \"alpha?beta\" },\n        { \"http://foo/bar#beta\", \"http\", \"foo\", 0, \"/bar\", NULL, NULL, \"beta\" },\n        { \"http://foo/bar?#beta\", \"http\", \"foo\", 0, \"/bar\", NULL, \"\", \"beta\" },\n        { \"http://foo/bar?alpha?beta\", \"http\", \"foo\", 0, \"/bar\", NULL, \"alpha?beta\", NULL },\n        { \"http://foo?alpha\", \"http\", \"foo\", 0, \"/\", NULL, \"alpha\", NULL },\n        { \"http://foo#beta\", \"http\", \"foo\", 0, \"/\", NULL, NULL, \"beta\" },\n\n        /* Examples from RFC39861.1.2: */\n        { \"ftp://ftp.is.co.za/rfc/rfc1808.txt\", \"ftp\", \"ftp.is.co.za\", 0, \"/rfc/rfc1808.txt\", NULL, NULL, NULL },\n        { \"http://www.ietf.org/rfc/rfc2396.txt\", \"http\", \"www.ietf.org\", 0, \"/rfc/rfc2396.txt\", NULL, NULL, NULL },\n        { \"ldap://[2001:db8::7]/c=GB?objectClass?one\", \"ldap\", \"[2001:db8::7]\", 0, \"/c=GB\", NULL, \"objectClass?one\", NULL },\n        { \"mailto:John.Doe@example.com\", \"mailto\", NULL, 0, \"John.Doe@example.com\", NULL, NULL, NULL }, \n        { \"news:comp.infosystems.www.servers.unix\", \"news\", NULL, 0, \"comp.infosystems.www.servers.unix\", NULL, NULL, NULL },\n        { \"tel:+1-816-555-1212\", \"tel\", NULL, 0, \"+1-816-555-1212\", NULL, NULL, NULL },\n        { \"telnet://192.0.2.16:80/\", \"telnet\", \"192.0.2.16\", 80, \"/\", NULL, NULL, NULL },\n        { \"urn:oasis:names:specification:docbook:dtd:xml:4.1.2\", \"urn\", NULL, 0, \n          \"oasis:names:specification:docbook:dtd:xml:4.1.2\", NULL}, \n\n        /* userinfo */\n        { \"ftp://jim:bob@jim.com\", \"ftp\", \"jim.com\", 0, \"/\", \"jim:bob\", NULL, NULL },\n        { \"ldap://fred:bloggs@fish.com/foobar\", \"ldap\", \"fish.com\", 0, \n          \"/foobar\", \"fred:bloggs\", NULL, NULL },\n\n        /* IPv6 literals: */\n        { \"http://[::1]/foo\", \"http\", \"[::1]\", 0, \"/foo\", NULL, NULL, NULL },\n        { \"http://[a:a:a:a::0]/foo\", \"http\", \"[a:a:a:a::0]\", 0, \"/foo\", NULL, NULL, NULL },\n        { \"http://[::1]:8080/bar\", \"http\", \"[::1]\", 8080, \"/bar\", NULL, NULL, NULL },\n        { \"ftp://[feed::cafe]:555\", \"ftp\", \"[feed::cafe]\", 555, \"/\", NULL, NULL, NULL },\n\n        /* Test RFC 6874 syntax, an extension of RFC 3987. */\n        { \"http://[fe80::cafe%25eth0]:555\", \"http\", \"[fe80::cafe%25eth0]\", 555, \"/\", NULL, NULL, NULL },\n        { \"http://[fe80::cafe%251]:555\", \"http\", \"[fe80::cafe%251]\", 555, \"/\", NULL, NULL, NULL },\n\n        { \"DAV:\", \"DAV\", NULL, 0, \"\", NULL, NULL, NULL },\n        \n        /* Some odd cases: heir-part and relative-ref will both match\n         * with a zero-length expansion of \"authority\" (since *\n         * reg-name can be zero-length); so a triple-slash URI-ref\n         * will be matched as \"//\" followed by a zero-length authority\n         * followed by a path of \"/\". */\n        { \"foo:///\", \"foo\", \"\", 0, \"/\", NULL, NULL, NULL },\n        { \"///\", NULL, \"\", 0, \"/\", NULL, NULL, NULL },\n        /* port grammar is \"*DIGIT\" so may be empty: */        \n        { \"ftp://[feed::cafe]:\", \"ftp\", \"[feed::cafe]\", 0, \"/\", NULL, NULL, NULL },\n        { \"ftp://[feed::cafe]:/\", \"ftp\", \"[feed::cafe]\", 0, \"/\", NULL, NULL, NULL },\n        { \"http://foo:/\", \"http\", \"foo\", 0, \"/\", NULL, NULL, NULL },\n\n        /* URI-references: */\n        { \"//foo.com/bar\", NULL, \"foo.com\", 0, \"/bar\", NULL, NULL, NULL },\n        { \"//foo.com\", NULL, \"foo.com\", 0, \"/\", NULL, NULL, NULL },\n        { \"//[::1]/foo\", NULL, \"[::1]\", 0, \"/foo\", NULL, NULL, NULL },\n        { \"/bar\", NULL, NULL, 0, \"/bar\", NULL, NULL, NULL }, /* path-absolute */\n        { \"foo/bar\", NULL, NULL, 0, \"foo/bar\", NULL, NULL, NULL }, /* path-noscheme */\n        { \"\", NULL, NULL, 0, \"\", NULL, NULL, NULL }, /* path-empty */\n\n        /* CVE-2007-0157: buffer under-read in 0.26.[012]. */\n        { \"http://webdav.org\\xFF\", \"http\", \"webdav.org\\xFF\", 0, \"/\", NULL, NULL, NULL },\n\n\t{ NULL }\n    };\n    int n;\n\n    for (n = 0; uritests[n].uri != NULL; n++) {\n\tne_uri res;\n\tconst struct test_uri *e = &uritests[n];\n\tONV(ne_uri_parse(e->uri, &res) != 0,\n\t    (\"'%s': parse failed\", e->uri));\n\tONV(res.port != e->port,\n\t    (\"'%s': parsed port was %d not %d\", e->uri, res.port, e->port));\n\tONCMP(e->scheme, res.scheme, e->uri, \"scheme\");\n\tONCMP(e->host, res.host, e->uri, \"host\");\n\tONV(strcmp(res.path, e->path),\n\t    (\"'%s': parsed path was '%s' not '%s'\", e->uri, res.path, e->path));\n        ONCMP(e->userinfo, res.userinfo, e->uri, \"userinfo\");\n        ONCMP(e->query, res.query, e->uri, \"query\");\n        ONCMP(e->fragment, res.fragment, e->uri, \"fragment\");\n\tne_uri_free(&res);\n    }\n\n    return OK;\n}\n\nstatic int failparse(void)\n{\n    static const char *uris[] = {\n        \"http://[::1/\",\n        \"http://[::1]f:80/\",\n        \"http://[::1]]:80/\",\n        \"http://foo/bar asda\",\n        \"http://fish/[foo]/bar\",\n        \"http://foo:80bar\",\n        \"http://foo:80:80/bar\",\n        \"http://foo:8000000000000000000000000000000000000000000000000/bar\",\n        \"http://foo:65536/bar\",\n        NULL\n    };\n    int n;\n    \n    for (n = 0; uris[n] != NULL; n++) {\n\tne_uri p;\n\tONV(ne_uri_parse(uris[n], &p) == 0,\n\t    (\"`%s' did not fail to parse\", uris[n]));\n\tne_uri_free(&p);\n    }\n\n    return 0;\n}\n\nstatic int unparse(void)\n{\n    const char *uris[] = {\n\t\"http://foo.com/bar\",\n\t\"https://bar.com/foo/wishbone\",\n\t\"http://www.random.com:8000/\",\n\t\"http://[::1]:8080/\",\n\t\"ftp://ftp.foo.bar/abc/def\",\n\t\"ftp://joe@bar.com/abc/def\",\n\t\"http://a/b?c#d\",\n\t\"http://a/b?c\",\n\t\"http://a/b#d\",\n        \"mailto:foo@bar.com\",\n        \"//foo.com/bar\",\n        \"//foo.com:8080/bar\",\n\tNULL\n    };\n    int n;\n\n    for (n = 0; uris[n] != NULL; n++) {\n\tne_uri parsed;\n\tchar *unp;\n\n\tONV(ne_uri_parse(uris[n], &parsed),\n\t    (\"failed to parse %s\", uris[n]));\n\t\n        if (parsed.port == 0 && parsed.scheme)\n            parsed.port = ne_uri_defaultport(parsed.scheme);\n\n\tunp = ne_uri_unparse(&parsed);\n\n\tONV(strcmp(unp, uris[n]),\n\t    (\"unparse got %s from %s\", unp, uris[n]));\n\t\n        ne_uri_free(&parsed);\n\tne_free(unp);\n    }\n\n    return OK;    \n}\n\n#define BASE \"http://a/b/c/d;p?q\"\n\nstatic int resolve(void)\n{\n    static const struct {\n        const char *base, *relative, *expected;\n    } ts[] = {\n        /* Examples from RFC39865.4: */\n        { BASE, \"g:h\", \"g:h\" },\n        { BASE, \"g\", \"http://a/b/c/g\" },\n        { BASE, \"./g\", \"http://a/b/c/g\" },\n        { BASE, \"g/\", \"http://a/b/c/g/\" },\n        { BASE, \"/g\", \"http://a/g\" },\n        { BASE, \"//g\", \"http://g/\" }, /* NOTE: modified to mandate non-empty path */\n        { BASE, \"?y\", \"http://a/b/c/d;p?y\" },\n        { BASE, \"g?y\", \"http://a/b/c/g?y\" },\n        { BASE, \"#s\", \"http://a/b/c/d;p?q#s\" },\n        { BASE, \"g#s\", \"http://a/b/c/g#s\" },\n        { BASE, \"g?y#s\", \"http://a/b/c/g?y#s\" },\n        { BASE, \";x\", \"http://a/b/c/;x\" },\n        { BASE, \"g;x\", \"http://a/b/c/g;x\" },\n        { BASE, \"g;x?y#s\", \"http://a/b/c/g;x?y#s\" },\n        { BASE, \"\", \"http://a/b/c/d;p?q\" },\n        { BASE, \".\", \"http://a/b/c/\" },\n        { BASE, \"./\", \"http://a/b/c/\" },\n        { BASE, \"..\", \"http://a/b/\" },\n        { BASE, \"../\", \"http://a/b/\" },\n        { BASE, \"../g\", \"http://a/b/g\" },\n        { BASE, \"../..\", \"http://a/\" },\n        { BASE, \"../../\", \"http://a/\" },\n        { BASE, \"../../g\", \"http://a/g\" },\n        { BASE, \"../../../g\", \"http://a/g\" },\n        { BASE, \"../../../../g\", \"http://a/g\" },\n        { BASE, \"/./g\", \"http://a/g\" },\n        { BASE, \"/../g\", \"http://a/g\" },\n        { BASE, \"g.\", \"http://a/b/c/g.\" },\n        { BASE, \".g\", \"http://a/b/c/.g\" },\n        { BASE, \"g..\", \"http://a/b/c/g..\" },\n        { BASE, \"..g\", \"http://a/b/c/..g\" },\n        { BASE, \"./../g\", \"http://a/b/g\" },\n        { BASE, \"./g/.\", \"http://a/b/c/g/\" },\n        { BASE, \"g/./h\", \"http://a/b/c/g/h\" },\n        { BASE, \"g/../h\", \"http://a/b/c/h\" },\n        { BASE, \"g;x=1/./y\", \"http://a/b/c/g;x=1/y\" },\n        { BASE, \"g;x=1/../y\", \"http://a/b/c/y\" },\n        { BASE, \"g?y/./x\", \"http://a/b/c/g?y/./x\" },\n        { BASE, \"g?y/../x\", \"http://a/b/c/g?y/../x\" },\n        { BASE, \"g#s/./x\", \"http://a/b/c/g#s/./x\" },\n        { BASE, \"g#s/../x\", \"http://a/b/c/g#s/../x\" },\n        { BASE, \"http:g\", \"http:g\" },\n        /* Additional examples: */\n        { BASE, \".\", \"http://a/b/c/\" },\n        { \"http://foo.com/alpha/beta\", \"../gamma\", \"http://foo.com/gamma\" },\n        { \"http://foo.com/alpha//beta\", \"../gamma\", \"http://foo.com/alpha/gamma\" },\n\n        { \"http://foo.com\", \"../gamma\", \"http://foo.com/gamma\" },\n        { \"\", \"zzz:.\", \"zzz:\" },\n        { \"\", \"zzz:./foo\", \"zzz:foo\" },\n        { \"\", \"zzz:../foo\", \"zzz:foo\" },\n        { \"\", \"zzz:/./foo\", \"zzz:/foo\" },\n        { \"\", \"zzz:/.\", \"zzz:/\" },\n        { \"\", \"zzz:/../\", \"zzz:/\" },\n        { \"\", \"zzz:.\", \"zzz:\" },\n        { \"\", \"zzz:..\", \"zzz:\" },\n        { \"\", \"zzz://foo@bar/\", \"zzz://foo@bar/\" },\n        { \"\", \"zzz://foo/?bar\", \"zzz://foo/?bar\" },\n        { \"zzz://foo/?bar\", \"//baz/?jam\", \"zzz://baz/?jam\" },\n        { \"zzz://foo/baz?biz\", \"\", \"zzz://foo/baz?biz\" },\n        { \"zzz://foo/baz\", \"\", \"zzz://foo/baz\" },\n        { \"//foo/baz\", \"\", \"//foo/baz\" },\n\n\n        { NULL, NULL, NULL }\n    };\n    size_t n;\n\n    for (n = 0; ts[n].base; n++) {\n        ne_uri base, relative, resolved;\n        char *actual;\n\n        ONV(ne_uri_parse(ts[n].base, &base),\n            (\"could not parse base URI '%s'\", ts[n].base));\n\n        ONV(ne_uri_parse(ts[n].relative, &relative),\n            (\"could not parse input URI '%s'\", ts[n].relative));\n\n        ONN(\"bad pointer was returned\", \n            ne_uri_resolve(&base, &relative, &resolved) != &resolved);\n\n        ONN(\"NULL path after resolve\", resolved.path == NULL);\n\n        actual = ne_uri_unparse(&resolved);\n        \n        ONCMP(ts[n].expected, actual, ts[n].relative, \"output mismatch\");\n        \n        ne_uri_free(&relative);\n        ne_uri_free(&resolved);\n        ne_uri_free(&base);\n        ne_free(actual);\n    }\n\n    return OK;\n}\n\nstatic int copy(void)\n{\n    static const char *ts[] = {\n        \"http://jim@foo.com:8080/bar?baz#bee\",\n        \"\",\n        NULL,\n    };\n    size_t n;\n\n    for (n = 0; ts[n]; n++) {\n        ne_uri parsed, parsed2;\n        char *actual;\n\n        ONV(ne_uri_parse(ts[n], &parsed), (\"could not parse URI '%s'\", ts[n]));\n        ONN(\"ne_uri_copy returned wrong pointer\",\n            ne_uri_copy(&parsed2, &parsed) != &parsed2);\n\n        actual = ne_uri_unparse(&parsed2);\n\n        ONCMP(ts[n], actual, \"copied URI\", \"unparsed URI\");\n\n        ne_uri_free(&parsed2);\n        ne_uri_free(&parsed);\n        ne_free(actual);\n    }\n\n    return OK;\n}\n\nne_test tests[] = {\n    T(simple),\n    T(simple_ssl),\n    T(no_path),\n    T(escapes),\n    T(parents),\n    T(compares),\n    T(cmp),\n    T(children),\n    T(slash),\n    T(default_port),\n    T(parse),\n    T(failparse),\n    T(unparse),\n    T(resolve),\n    T(copy),\n    T(NULL)\n};\n"
  },
  {
    "path": "test/util-socks.c",
    "content": "/* \n   SOCKS server utils.\n   Copyright (C) 2008, 2009, Joe Orton <joe@manyfish.co.uk>\n\n   This program is free software; you can redistribute it and/or modify\n   it under the terms of the GNU General Public License as published by\n   the Free Software Foundation; either version 2 of the License, or\n   (at your option) any later version.\n  \n   This program is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU General Public License for more details.\n  \n   You should have received a copy of the GNU General Public License\n   along with this program; if not, write to the Free Software\n   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\n*/\n\n#include \"config.h\"\n\n#include <sys/types.h>\n\n#ifdef HAVE_STDLIB_H\n#include <stdlib.h>\n#endif\n#ifdef HAVE_STRING_H\n#include <string.h>\n#endif\n#include <time.h> /* for time() */\n\n#include \"ne_socket.h\"\n#include \"ne_utils.h\"\n#include \"ne_alloc.h\"\n\n#include \"child.h\"\n#include \"tests.h\"\n#include \"utils.h\"\n\n#define V5_METH_NONE 0x00\n#define V5_METH_AUTH 0x02\n#define V5_ADDR_IPV4 0x01\n#define V5_ADDR_FQDN 0x03\n#define V5_ADDR_IPV6 0x04\n\nstatic int read_socks_string(ne_socket *sock, const char *ctx,\n                             unsigned char *buf, unsigned int *olen)\n{\n    unsigned char len;\n    ssize_t ret;\n\n    ret = ne_sock_read(sock, (char *)&len, 1);\n    ONV(ret != 1, (\"%s length read failed: %s\", ctx, ne_sock_error(sock)));\n\n    ONV(len == 0, (\"%s gave zero-length string\", ctx));\n\n    ret = ne_sock_fullread(sock, (char *)buf, len);\n    ONV(ret != 0, (\"%s string read failed, got %\" NE_FMT_SSIZE_T \n                   \" bytes (%s)\", ctx, ret, ne_sock_error(sock)));\n    \n    *olen = len;\n\n    return OK;    \n}\n\nstatic int read_socks_byte(ne_socket *sock, const char *ctx,\n                           unsigned char *buf)\n{\n    ONV(ne_sock_read(sock, (char *)buf, 1) != 1, \n        (\"%s byte read failed: %s\", ctx, ne_sock_error(sock)));\n    return OK;    \n}\n\nstatic int expect_socks_byte(ne_socket *sock, const char *ctx,\n                             unsigned char c)\n{\n    unsigned char b;\n\n    CALL(read_socks_byte(sock, ctx, &b));\n\n    ONV(b != c, (\"%s got byte %hx not %hx\", ctx, b, c));\n    \n    return OK;\n}    \n\nstatic int read_socks_0string(ne_socket *sock, const char *ctx,\n                              unsigned char *buf, unsigned *len)\n{\n    unsigned char *end = buf + *len, *p = buf;\n\n    while (p < end) {\n        CALL(read_socks_byte(sock, ctx, p));\n\n        if (*p == '\\0')\n            break;\n        p++;\n        \n    } \n\n    *len = p - buf;\n\n    return OK;\n}\n\nint socks_server(ne_socket *sock, void *userdata)\n{\n    struct socks_server *srv = userdata;\n    unsigned char buf[1024];\n    unsigned int len, port, version;\n    unsigned char atype;\n    ssize_t ret;\n\n    version = srv->version == NE_SOCK_SOCKSV5 ? 5 : 4;\n\n    ne_sock_read_timeout(sock, 5);\n\n    CALL(expect_socks_byte(sock, \"client version\", version));\n\n    if (version != 5) {\n        unsigned char raw[16];\n\n        CALL(expect_socks_byte(sock, \"v4 command\", 0x01));\n\n        ret = ne_sock_fullread(sock, (char *)buf, 6);\n        ONV(ret != 0,\n            (\"v4 address read failed with %\" NE_FMT_SSIZE_T\n             \" (%s)\", ret, ne_sock_error(sock)));\n\n        ONN(\"bad v4A bogus address\",\n            srv->version == NE_SOCK_SOCKSV4A && srv->expect_addr == NULL\n            && memcmp(buf + 2, \"\\0\\0\\0\", 3) != 0 && buf[6] != 0);\n\n        ONN(\"v4 server with no expected address! fail\",\n            srv->version == NE_SOCK_SOCKSV4 && srv->expect_addr == NULL);\n\n        if (srv->expect_addr) {\n            ONN(\"v4 address mismatch\", \n                memcmp(ne_iaddr_raw(srv->expect_addr, raw), buf + 2, 4) != 0);        \n        }\n\n        port = (buf[0] << 8) | buf[1];\n        ONV(port != srv->expect_port,\n            (\"got bad v4 port %u, expected %u\", port, srv->expect_port));\n        \n        len = sizeof buf;\n        CALL(read_socks_0string(sock, \"v4 username read\", buf, &len));\n\n        ONV(srv->username == NULL && len, (\"unexpected v4 username %s\", buf));\n        ONV(srv->username && !len, \n            (\"no v4 username given, expected %s\", srv->username));\n        ONV(srv->username && len && strcmp(srv->username, (char *)buf),\n            (\"bad v4 username, expected %s got %s\", srv->username, buf));\n        \n        if (srv->expect_addr == NULL) {\n            len = sizeof buf;\n            CALL(read_socks_0string(sock, \"v4A hostname read\", buf, &len));\n            ONV(strcmp(srv->expect_fqdn, (char *)buf) != 0,\n                (\"bad v4A hostname: %s not %s\", buf, srv->expect_fqdn));\n        }\n\n        { \n            static const char msg[] = \"\\x00\\x5A\"\n                \"\\x00\\x00\" \"\\x00\\x00\\x00\\x00\"\n                \"ok!\\n\";\n        \n            if (srv->say_hello)\n                CALL(full_write(sock, msg, 12));\n            else\n                CALL(full_write(sock, msg, 8));\n        }\n    \n        return srv->server(sock, srv->userdata);\n    }\n\n    CALL(read_socks_string(sock, \"client method list\", buf, &len));\n\n    if (srv->failure == fail_init_vers) {\n        CALL(full_write(sock, \"\\x01\\x02\", 2));\n        return OK;\n    }\n    else if (srv->failure == fail_init_close) {\n        return OK;\n    }\n    else if (srv->failure == fail_init_trunc) {\n        CALL(full_write(sock, \"\\x05\", 1));\n        return OK;\n    }\n    else if (srv->failure == fail_no_auth) {\n        CALL(full_write(sock, \"\\x05\\xff\", 2));\n        return OK;\n    }\n    else if (srv->failure == fail_bogus_auth) {\n        CALL(full_write(sock, \"\\x05\\xfe\", 2));\n        return OK;\n    }\n\n    ONN(\"client did not advertise no-auth method\",\n        memchr(buf, V5_METH_NONE, len) == NULL);\n    \n    if (srv->username) {\n        int match = 0;\n         \n        ONN(\"client did not advertise authn method\",\n            memchr(buf, V5_METH_AUTH, len) == NULL);\n        \n        CALL(full_write(sock, \"\\x05\\x02\", 2));\n        \n        CALL(expect_socks_byte(sock, \"client auth version\", 0x01));\n\n        CALL(read_socks_string(sock, \"client username\", buf, &len));\n        \n        match = len == strlen(srv->username)\n            && memcmp(buf, srv->username, len) == 0;\n        \n        CALL(read_socks_string(sock, \"client password\", buf, &len));\n        \n        match = match && len == strlen(srv->password)\n            && memcmp(buf, srv->password, len) == 0;\n\n        if (srv->failure == fail_auth_close) {\n            return OK;\n        }\n\n        if (match && srv->failure != fail_auth_denied) {\n            CALL(full_write(sock, \"\\x01\\x00\", 2));\n        }\n        else {\n            CALL(full_write(sock, \"\\x01\\x01\", 2));\n        }\n        \n        if (srv->failure == fail_auth_denied) {\n            return OK;\n        }\n    }\n    else {\n        CALL(full_write(sock, \"\\x05\\x00\", 2));\n    }\n    \n    CALL(expect_socks_byte(sock, \"command version\", version));\n\n    CALL(expect_socks_byte(sock, \"command number\", 0x01));\n    CALL(read_socks_byte(sock, \"reserved byte\", buf));\n\n    CALL(read_socks_byte(sock, \"address type\", &atype));\n\n    ONN(\"bad address type byte\", \n        (atype != V5_ADDR_IPV4 && atype != V5_ADDR_IPV6\n         && atype != V5_ADDR_FQDN));\n\n    if (atype == V5_ADDR_FQDN) {\n        ONN(\"unexpected FQDN from client\", srv->expect_fqdn == NULL);\n        CALL(read_socks_string(sock, \"read FQDN\", buf, &len));\n        ONV(len != strlen(srv->expect_fqdn)\n            || memcmp(srv->expect_fqdn, buf, len) != 0,\n            (\"FQDN mismatch: %.*s not %s\", len, buf, \n             srv->expect_fqdn));\n    }\n    else {\n        unsigned char raw[16];\n\n        ONN(\"unexpected IP literal from client\", srv->expect_addr == NULL);\n\n        ONV((atype == V5_ADDR_IPV4\n             && ne_iaddr_typeof(srv->expect_addr) != ne_iaddr_ipv4)\n            || (atype == V5_ADDR_IPV6\n                && ne_iaddr_typeof(srv->expect_addr) != ne_iaddr_ipv6),\n            (\"address type mismatch: %hx not %d\",\n             atype, ne_iaddr_typeof(srv->expect_addr)));\n\n        len = atype == V5_ADDR_IPV4 ? 4 : 16;\n        ret = ne_sock_fullread(sock, (char *)buf, len);\n        ONV(ret != 0,\n            (\"address read failed with %\" NE_FMT_SSIZE_T\n             \" (%s)\", ret, ne_sock_error(sock)));\n\n        ne_iaddr_raw(srv->expect_addr, raw);\n        \n        ONN(\"address mismatch\", memcmp(raw, buf, len) != 0);        \n    }\n\n    CALL(read_socks_byte(sock, \"port high byte\", buf));\n    CALL(read_socks_byte(sock, \"port low byte\", buf + 1));\n    \n    port = (buf[0] << 8) | buf[1];\n    ONV(port != srv->expect_port,\n        (\"got bad port %u, expected %u\", port, srv->expect_port));\n\n    {\n        static const char msg[] = \n            \"\\x05\\x00\\x00\"\n            \"\\x01\" \"\\x00\\x00\\x00\\x00\"\n            \"\\x00\\x00\"\n            \"ok!\\n\";\n\n        if (srv->say_hello)\n            CALL(full_write(sock, msg, 14));\n        else\n            CALL(full_write(sock, msg, 10));\n    }\n        \n    \n    return srv->server(sock, srv->userdata);\n}\n"
  },
  {
    "path": "test/util-tests.c",
    "content": "/* \n   utils tests\n   Copyright (C) 2001-2006, Joe Orton <joe@manyfish.co.uk>\n\n   This program is free software; you can redistribute it and/or modify\n   it under the terms of the GNU General Public License as published by\n   the Free Software Foundation; either version 2 of the License, or\n   (at your option) any later version.\n  \n   This program is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU General Public License for more details.\n  \n   You should have received a copy of the GNU General Public License\n   along with this program; if not, write to the Free Software\n   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\n*/\n\n#include \"config.h\"\n\n#ifdef HAVE_STDLIB_H\n#include <stdlib.h>\n#endif\n#ifdef HAVE_STRING_H\n#include <string.h>\n#endif\n#ifdef HAVE_STDINT_H\n#include <stdint.h>\n#endif\n\n#include \"ne_utils.h\"\n#include \"ne_md5.h\"\n#include \"ne_alloc.h\"\n#include \"ne_dates.h\"\n#include \"ne_string.h\"\n\n#include \"tests.h\"\n\nstatic const struct {\n    const char *status;\n    int major, minor, code;\n    const char *rp;\n} accept_sl[] = {\n    /* These are really valid. */\n    { \"HTTP/1.1 200 OK\", 1, 1, 200, \"OK\" },\n    { \"HTTP/9.9 599 OK\", 9, 9, 599, \"OK\" },\n    { \"HTTP/1.0 123 OK-is-OK1234\", 1, 0, 123, \"OK-is-OK1234\" },\n    { \"HTTP/1.1 100 Alpha\\tBeta\", 1, 1, 100, \"Alpha Beta\" }, /* should be cleaned. */\n    { \"HTTP/1.1 100 Alpha  Beta\", 1, 1, 100, \"Alpha  Beta\" },\n    { \"HTTP/1.1 100 fØØbÆr\", 1, 1, 100, \"f    b  r\" }, /* UTF-8 should be cleaned */\n\n    /* these aren't really valid but we should be able to parse them. */\n    { NULL }\n};\n\nstatic const char *const bad_sl[] = {\n    \"\",\n    \"HTTP/1.1 1000 OK\",\n    \"HTTP/1.1 1000\",\n    \"HTTP/-1.1 100 OK\",\n    \"HTTP/1.1 -100 OK\",\n    \"HTTP/ 200 OK\",\n    \"HTTP/\",\n    \"HTTP/1.1A 100 OK\",\n    \"HTTP/1.\",\n    \"HTTP/1.1 1\",\n    \"Fish/1.1 100 OK\",\n    \"HTTP/1.1 10\",\n    \"HTTP\",\n    \"H\\0TP/1.1 100 OK\",\n\n    /* Previously allowed, now disallowed. */\n    \"HTTP/1.1   200   OK\",\n    \"HTTP/1.1   200 \\t  OK\",\n    \"   HTTP/1.1 200 OK\",\n    \"Norman is a dog HTTP/1.1 200 OK\",\n    \"HTTP/1.1000 100 OK\",\n    \"HTTP/1000.1000 100 OK\",\n    \"HTTP/00001.1 100 OK\",\n    \"HTTP/1.00001 100 OK\",\n    \"HTTP/99.99 100 OK\",\n    \"HTTP/1.1 600 OK\",\n\n    NULL\n};  \n\nstatic int status_lines(void)\n{\n    ne_status s;\n    int n;\n\n    for (n = 0; accept_sl[n].status != NULL; n++) {\n\tONV(ne_parse_statusline(accept_sl[n].status, &s),\n\t    (\"valid #%d: parsing '%s' failed\", n, accept_sl[n].status));\n\tONV(accept_sl[n].major != s.major_version, (\"valid #%d: major\", n));\n\tONV(accept_sl[n].minor != s.minor_version, (\"valid #%d: minor\", n));\n\tONV(accept_sl[n].code != s.code, (\"valid #%d: code %d not %d\", n, s.code, accept_sl[n].code));\n\tONV(strcmp(accept_sl[n].rp, s.reason_phrase), \n\t    (\"valid #%d: reason phrase [%s] not [%s]\", n, s.reason_phrase, accept_sl[n].rp));\n        ne_free(s.reason_phrase);\n        memset(&s, 0, sizeof s);\n    }\n    \n    for (n = 0; bad_sl[n] != NULL; n++) {\n\tONV(ne_parse_statusline(bad_sl[n], &s) == 0, \n\t    (\"invalid #%d parsed OK - [%s]\", n, bad_sl[n]));\n    }\n\n    return OK;\n}\n\n/* Write MD5 of 'len' bytes of 'str' to 'digest' */\nstatic const unsigned char *digest_md5(const char *data, size_t len,\n                                 unsigned int digest[4])\n{\n    struct ne_md5_ctx *ctx;\n\n#define CHUNK 100\n    ctx = ne_md5_create_ctx();\n    if (!ctx) {\n        return (unsigned char *)\"NO-MD5-SUPPORT\";\n    }        \n    /* exercise the buffering interface */\n    while (len > CHUNK) {\n        ne_md5_process_bytes(data, CHUNK, ctx);\n        len -= CHUNK;\n        data += CHUNK;\n    }\n    ne_md5_process_bytes(data, len, ctx);\n    ne_md5_finish_ctx(ctx, digest);\n    ne_md5_destroy_ctx(ctx);\n\n    return (unsigned char *)digest;\n}\n\nstatic int md5(void)\n{\n    unsigned int buf[4], buf2[4] = {0};\n    char ascii[33] = {0};\n    char zzzs[500];\n\n    ne_md5_to_ascii(digest_md5(\"\", 0, buf), ascii);\n    ONN(\"MD5(null)\", strcmp(ascii, \"d41d8cd98f00b204e9800998ecf8427e\"));\n    \n    ne_md5_to_ascii(digest_md5(\"foobar\", 7, buf), ascii);\n    ONN(\"MD5(foobar)\", strcmp(ascii, \"b4258860eea29e875e2ee4019763b2bb\"));\n\n    /* $ perl -e 'printf \"z\"x500' | md5sum\n     * 8b9323bd72250ea7f1b2b3fb5046391a  - */\n    memset(zzzs, 'z', sizeof zzzs);\n    ne_md5_to_ascii(digest_md5(zzzs, sizeof zzzs, buf), ascii);\n    ONN(\"MD5(\\\"z\\\"x512)\", strcmp(ascii, \"8b9323bd72250ea7f1b2b3fb5046391a\"));\n\n    ne_ascii_to_md5(ascii, (unsigned char *)buf2);\n    ON(memcmp(buf, buf2, 16));\n    \n    return OK;\n}\n\nstatic int md5_alignment(void)\n{\n    char *bb = ne_malloc(66);\n    struct ne_md5_ctx *ctx;\n\n    /* regression test for a bug in md5.c in <0.15.0 on SPARC, where\n     * the process_bytes function would SIGBUS if the buffer argument\n     * isn't 32-bit aligned. Won't trigger on x86 though. */\n    ctx = ne_md5_create_ctx();\n    ONN(\"could not create MD5 context\", ctx == NULL);\n    ne_md5_process_bytes(bb + 1, 65, ctx);\n    ne_md5_destroy_ctx(ctx);\n    ne_free(bb);\n\n    return OK;\n}\n\n#define INIT_MD5 \"0123456789abcdeffedcba9876543210\"\n\nstatic int md5_read(void)\n{\n    union {\n        unsigned int int32[4];\n        unsigned char buf[16];\n    } u;\n    struct ne_md5_ctx *ctx = ne_md5_create_ctx();\n    void *rv;\n    char hex[33];\n\n    rv = ne_md5_read_ctx(ctx, u.buf);\n    if (rv == NULL) {\n        ne_md5_destroy_ctx(ctx);\n        return SKIP;\n    }\n    ONN(\"bogus return value\", rv != u.buf);\n\n    ne_md5_to_ascii(u.buf, hex);\n\n    ONV(strcmp(INIT_MD5, hex) != 0,\n        (\"read context was %s not %s\", hex, INIT_MD5));\n\n    ne_md5_destroy_ctx(ctx);\n\n    return OK;\n}\n\nstatic const struct {\n    const char *str;\n    time_t time;\n    enum { d_rfc1123, d_iso8601, d_rfc1036, d_asctime } type;\n} good_dates[] = {\n    { \"Fri, 08 Jun 2001 22:59:46 GMT\", 992041186, d_rfc1123 },\n    { \"Friday, 08-Jun-01 22:59:46 GMT\", 992041186, d_rfc1036 },\n    { \"Wednesday, 06-Jun-01 22:59:46 GMT\", 991868386, d_rfc1036 },\n    { \"Wed Jun 06 22:59:46 2001\", 991868386, d_asctime },\n    /* some different types of ISO8601 dates. */\n    { \"2001-06-08T22:59:46Z\", 992041186, d_iso8601 },\n    { \"2001-06-08T22:59:46.9Z\", 992041186, d_iso8601 },\n    { \"2001-06-08T26:00:46+03:01\", 992041186, d_iso8601 },\n    { \"2001-06-08T20:58:46-02:01\", 992041186, d_iso8601 },\n    { NULL }\n};\n\nstatic int parse_dates(void)\n{\n    int n;\n\n    for (n = 0; good_dates[n].str != NULL; n++) {\n\ttime_t res;\n\tconst char *str = good_dates[n].str;\n\n\tswitch (good_dates[n].type) {\n\tcase d_rfc1036: res = ne_rfc1036_parse(str); break;\n\tcase d_iso8601: res = ne_iso8601_parse(str); break;\n\tcase d_rfc1123: res = ne_rfc1123_parse(str); break;\n\tcase d_asctime: res = ne_asctime_parse(str); break;\n\tdefault: res = -1; break;\n\t}\n\t\n\tONV(res == -1, (\"date %d parse\", n));\n\t\n#define FT \"%\" NE_FMT_TIME_T\n\tONV(res != good_dates[n].time, (\n\t    \"date %d incorrect (\" FT \" not \" FT \")\", n,\n\t    res, good_dates[n].time));\n    }\n\n    return OK;\n}\n\n#define BAD_DATE(format, result) \\\n    ONN(format \" date parse must fail\", result != -1)\n\n/* Test for bad dates; trigger segfaults in ne_rfc1036_parse() in\n * <=0.24.5. */\nstatic int bad_dates(void)\n{\n    static const char *dates[] = {\n        \"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\",\n        \"Friday, 08-Jun-01\",\n    };\n    size_t n;\n    \n    for (n = 0; n < sizeof(dates)/sizeof(dates[0]); n++) {\n        BAD_DATE(\"rfc1036\", ne_rfc1036_parse(dates[n]));\n        BAD_DATE(\"iso8601\", ne_iso8601_parse(dates[n]));\n        BAD_DATE(\"rfc1123\", ne_rfc1123_parse(dates[n]));\n        BAD_DATE(\"asctime\", ne_asctime_parse(dates[n]));\n    }\n\n#if SIZEOF_TIME_T == 8 && defined(INT64_MAX)\n    {\n        char *rv = ne_rfc1123_date(INT64_MAX);\n\n        ONV(rv != NULL,\n            (\"RFC1123 date conversion surprisingly worked for INT64_MAX: %s\",\n             rv));\n    }\n#endif\n\n    return OK;\n}\n\n#define GOOD(n,m,msg) ONV(ne_version_match(n,m), \\\n(\"match of \" msg \" failed (%d.%d)\", n, m))\n#define BAD(n,m,msg) ONV(ne_version_match(n,m) == 0, \\\n(\"match of \" msg \" succeeded (%d.%d)\", n, m))\n\nstatic int versioning(void)\n{\n    GOOD(NE_VERSION_MAJOR, NE_VERSION_MINOR, \"current version\");\n    BAD(NE_VERSION_MAJOR + 1, 0, \"later major\");\n    BAD(NE_VERSION_MAJOR, NE_VERSION_MINOR + 1, \"later minor\");\n#if NE_VERSION_MINOR > 0\n    GOOD(NE_VERSION_MAJOR, NE_VERSION_MINOR - 1, \"previous minor\");\n#endif\n\n#if NE_VERSION_MAJOR > 1\n    BAD(NE_VERSION_MAJOR - 1, 0, \"earlier major\");\n#else\n\n#if NE_VERSION_MAJOR == 0\n    BAD(1, 0, \"later major\");\n    BAD(1, NE_VERSION_MINOR, \"later major\");\n#endif\n    /* Note that 0.28 thru 1.x maintain backwards compatibility to\n     * 0.27 */\n    BAD(0, 26, \"minor version before 0.27\");\n    GOOD(0, 27, \"current version back-compat to 0.27\");\n    GOOD(0, 28, \"current version back-compat to 0.28\");\n    GOOD(0, 29, \"current version back-compat to 0.29\");\n    GOOD(0, 30, \"current version back-compat to 0.30\");\n#endif\n\n    return OK;\n}\n\n#undef GOOD\n#undef BAD\n\n/* basic ne_version_string() sanity tests */\nstatic int version_string(void)\n{\n    char buf[1024];\n    \n    ne_snprintf(buf, sizeof buf, \"%s\", ne_version_string());\n    \n    NE_DEBUG(NE_DBG_HTTP, \"Version string: %s\\n\", buf);\n\n    ONN(\"version string too long\", strlen(buf) > 200);\n    ONN(\"version string contained newline\", strchr(buf, '\\n') != NULL);\n\n    return OK;    \n}\n\nstatic int version_library(void)\n{\n    const char *ver;\n\n    ver = ne_version_library();\n    ONN(\"ne_version_library returned NULL\", ver == NULL);\n    ONN(\"ne_version_library returned empty string\", strlen(ver) == 0);\n\n    /* Version string should contain at least a digit */\n    ONV(strspn(ver, \"0123456789.-dev\") != strlen(ver),\n        (\"version string '%s' contains suprising digits\", ver));\n    return OK;\n}\n\nstatic int support(void)\n{\n#ifdef NE_HAVE_SSL\n    ONN(\"SSL support not advertised\", !ne_has_support(NE_FEATURE_SSL));\n#else\n    ONN(\"SSL support advertised\", ne_has_support(NE_FEATURE_SSL));\n#endif\n#ifdef NE_HAVE_ZLIB\n    ONN(\"zlib support not advertised\", !ne_has_support(NE_FEATURE_ZLIB));\n#else\n    ONN(\"zlib support advertised\", ne_has_support(NE_FEATURE_ZLIB));\n#endif\n#ifdef NE_HAVE_IPV6\n    ONN(\"IPv6 support not advertised\", !ne_has_support(NE_FEATURE_IPV6));\n#else\n    ONN(\"IPv6 support advertised\", ne_has_support(NE_FEATURE_IPV6));\n#endif\n#ifdef NE_HAVE_LFS\n    ONN(\"LFS support not advertised\", !ne_has_support(NE_FEATURE_LFS));\n#else\n    ONN(\"LFS support advertised\", ne_has_support(NE_FEATURE_LFS));\n#endif\n#ifdef NE_HAVE_TS_SSL\n    ONN(\"Thread-safe SSL support not advertised\", \n        !ne_has_support(NE_FEATURE_TS_SSL));\n#else\n    ONN(\"Thread-safe SSL support advertised\", \n        ne_has_support(NE_FEATURE_TS_SSL));\n#endif\n#ifdef NE_HAVE_I18N\n    ONN(\"i18n support not advertised\", \n        !ne_has_support(NE_FEATURE_I18N));\n#else\n    ONN(\"i18n SSL support advertised\", \n        ne_has_support(NE_FEATURE_I18N));\n#endif\n#ifdef NE_HAVE_GSSAPI\n    ONN(\"GSSAPI support not advertised\", \n        !ne_has_support(NE_FEATURE_GSSAPI));\n#else\n    ONN(\"GSSAPI support advertised\", \n        ne_has_support(NE_FEATURE_GSSAPI));\n#endif\n#ifdef NE_HAVE_LIBPXY\n    ONN(\"libproxy support not advertised\", \n        !ne_has_support(NE_FEATURE_LIBPXY));\n#else\n    ONN(\"libproxy support advertised\", \n        ne_has_support(NE_FEATURE_LIBPXY));\n#endif\n#ifdef NE_HAVE_NTLM\n    ONN(\"Libntlm support not advertised\", \n        !ne_has_support(NE_FEATURE_NTLM));\n#else\n    ONN(\"Libntlm support advertised\", \n        ne_has_support(NE_FEATURE_NTLM));\n#endif\n    return OK;\n}\n\nne_test tests[] = {\n    T(status_lines),\n    T(md5),\n    T(md5_alignment),\n    T(md5_read),\n    T(parse_dates),\n    T(bad_dates),\n    T(versioning),\n    T(version_string),\n    T(version_library),\n    T(support),\n    T(NULL)\n};\n"
  },
  {
    "path": "test/utils.c",
    "content": "/* \n   Utility functions for HTTP client tests\n   Copyright (C) 2001-2026, Joe Orton <joe@manyfish.co.uk>\n\n   This program is free software; you can redistribute it and/or modify\n   it under the terms of the GNU General Public License as published by\n   the Free Software Foundation; either version 2 of the License, or\n   (at your option) any later version.\n  \n   This program is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU General Public License for more details.\n  \n   You should have received a copy of the GNU General Public License\n   along with this program; if not, write to the Free Software\n   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\n*/\n\n#include \"config.h\"\n\n#ifdef HAVE_UNISTD_H\n#include <unistd.h> /* for sleep() */\n#endif\n#ifdef HAVE_STDLIB_H\n#include <stdlib.h>\n#endif\n#include <fcntl.h>\n#include <netinet/in.h>\n#include <arpa/inet.h>\n\n#include \"ne_session.h\"\n#include \"ne_string.h\"\n\n#include \"child.h\"\n#include \"tests.h\"\n#include \"utils.h\"\n\nstatic char session_host[128];\nunsigned int session_port;\n\nint serve_response(ne_socket *s, const char *response)\n{\n    CALL(discard_request(s));\n    CALL(discard_body(s));\n    ONN(\"failed to send response\", SEND_STRING(s, response));\n    return OK;\n}    \n\nint single_serve_string(ne_socket *s, void *userdata)\n{\n    const char *str = userdata;\n    return serve_response(s, str);\n}\n\nint double_serve_sstring(ne_socket *s, void *userdata)\n{\n    struct double_serve_args *args = userdata;\n    struct string *str;\n\n    CALL(discard_request(s));\n    CALL(discard_body(s));\n    \n    str = &args->first;\n    NE_DEBUG(NE_DBG_SOCKET, \"Serving string: [[[%.*s]]]\\n\",\n\t     (int)str->len, str->data);\n    ONN(\"write failed\", ne_sock_fullwrite(s, str->data, str->len));\n\n    CALL(discard_request(s));\n    CALL(discard_body(s));\n\n    str = &args->second;\n    NE_DEBUG(NE_DBG_SOCKET, \"Serving string: [[[%.*s]]]\\n\",\n\t     (int)str->len, str->data);\n    ONN(\"write failed\", ne_sock_fullwrite(s, str->data, str->len));\n\n    return OK;\n}\n\nint serve_buffer(ne_socket *s, void *userdata)\n{\n    ne_buffer *buf = userdata;\n    CALL(discard_request(s));\n    CALL(discard_body(s));\n    ONN(\"failed to send response\", server_send(s, buf->data, buf->used-1));\n    return OK;\n}\n\nint sleepy_server(ne_socket *sock, void *userdata)\n{\n    sleep(10);\n    return 0;\n}\n\nint many_serve_string(ne_socket *s, void *userdata)\n{\n    int n;\n    struct many_serve_args *args = userdata;\n    \n    for (n = 0; n < args->count; n++) {\n\tNE_DEBUG(NE_DBG_HTTP, \"Serving response %d\\n\", n);\n\tCALL(serve_response(s, args->str));\n    }\n\n    return OK;\n}\n\nint any_request(ne_session *sess, const char *uri)\n{\n    ne_request *req = ne_request_create(sess, \"GET\", uri);\n    int ret = ne_request_dispatch(req);\n    ne_request_destroy(req);\n    return ret;\n}\n\nint any_2xx_request_method(ne_session *sess, const char *method, const char *uri)\n{\n    ne_request *req = ne_request_create(sess, method, uri);\n    int ret = ne_request_dispatch(req);\n    int klass = ne_get_status(req)->klass;\n    const char *context = ne_get_response_header(req, \"X-Neon-Context\");\n    if (ret != NE_OK || klass != 2) {\n        if (context)\n            t_context(\"request failed, server error: %s\", context);\n        else\n            t_context(\"request failed: %s\", ne_get_error(sess));\n        ret = FAIL;\n    }\n    else {\n        ret = OK;\n    }\n    ne_request_destroy(req);\n    return ret;\n}\n\nint any_2xx_request(ne_session *sess, const char *uri)\n{\n    return any_2xx_request_method(sess, \"GET\", uri);\n}\n\nint any_2xx_request_body(ne_session *sess, const char *uri)\n{\n    ne_request *req = ne_request_create(sess, \"GET\", uri);\n#define BSIZE 5000\n    char *body = memset(ne_malloc(BSIZE), 'A', BSIZE);\n    int ret;\n    ne_set_request_body_buffer(req, body, BSIZE);\n    ret = ne_request_dispatch(req);\n    ne_free(body);\n    ONV(ret != NE_OK || ne_get_status(req)->klass != 2,\n\t(\"request failed: %s\", ne_get_error(sess)));\n    ne_request_destroy(req);\n    return ret;\n}\n\nint serve_sstring(ne_socket *sock, void *ud)\n{\n    struct string *str = ud;\n\n    NE_DEBUG(NE_DBG_SOCKET, \"Serving string: [[[%.*s]]]\\n\",\n\t     (int)str->len, str->data);\n\n    ONN(\"write failed\", ne_sock_fullwrite(sock, str->data, str->len));\n    \n    return 0;\n}\n\nint serve_sstring_slowly(ne_socket *sock, void *ud)\n{\n    struct string *str = ud;\n    size_t n;\n\n    NE_DEBUG(NE_DBG_SOCKET, \"Slowly serving string: [[[%.*s]]]\\n\",\n\t     (int)str->len, str->data);\n    \n    for (n = 0; n < str->len; n++) {\n\tONN(\"write failed\", ne_sock_fullwrite(sock, &str->data[n], 1));\n\tminisleep();\n    }\n    \n    return 0;\n}\n\nint serve_infinite(ne_socket *sock, void *ud)\n{\n    struct infinite *i = ud;\n\n    CALL(discard_request(sock));\n\n    SEND_STRING(sock, i->header);\n\n    while (server_send(sock, i->repeat, strlen(i->repeat)) == 0)\n        /* nullop */;\n    \n    return OK;\n}\n\nint full_write(ne_socket *sock, const char *data, size_t len)\n{\n    int ret = ne_sock_fullwrite(sock, data, len);\n    NE_DEBUG(NE_DBG_SOCKET, \"wrote: [%.*s]\\n\", (int)len, data);\n    ONV(ret, (\"write failed (%d): %s\", ret, ne_sock_error(sock)));\n    return OK;\n}\n\nstatic const char *localhost_session_host(void)\n{\n    if (get_lh_family() == AF_INET6) {\n        ne_snprintf(session_host, sizeof session_host, \"[%s]\", get_lh_addr());\n    }\n    else {\n        ne_strnzcpy(session_host, get_lh_addr(), sizeof session_host);\n    }\n    return session_host;\n}\n\nint multi_session_server(ne_session **sess, const char *scheme, int count,\n                         server_fn fn, void *userdata)\n{\n    CALL(new_spawn_server(count, fn, userdata, &session_port));\n\n    *sess = ne_session_create(scheme, localhost_session_host(), session_port);\n\n    NE_DEBUG(NE_DBG_HTTP, \"test: Created session for %s://%s:%u\\n\",\n             scheme, session_host, session_port);\n    return OK;\n}\n\nconst char *get_session_host(void)\n{\n    return session_host;\n}\n\nunsigned int get_session_port(void)\n{\n    return session_port;\n}\n\nint session_server(ne_session **sess, server_fn fn, void *userdata)\n{\n    return multi_session_server(sess, \"http\", 1, fn, userdata);\n}\n\nint proxied_multi_session_server(int count, ne_session **sess,\n                                 const char *scheme, const char *host,\n                                 unsigned int fakeport,\n                                 server_fn fn, void *userdata)\n{\n    CALL(new_spawn_server(count, fn, userdata, &session_port));\n    \n    *sess = ne_session_create(scheme, host, fakeport);\n\n    NE_DEBUG(NE_DBG_HTTP, \"test: Using proxied session to port %u.\\n\", session_port);\n\n    ne_session_proxy(*sess, localhost_session_host(), session_port);\n\n    return OK;\n}\n\n\nint proxied_session_server(ne_session **sess, const char *scheme,\n                           const char *host, unsigned int fakeport,\n                           server_fn fn, void *userdata)\n{\n    return proxied_multi_session_server(1, sess, scheme, host, fakeport,\n                                        fn, userdata);\n}\n\nstatic void fakesess_destroy(void *userdata)\n{\n    ne_inet_addr *addr = userdata;\n\n    ne_iaddr_free(addr);\n}\n\nint fakeproxied_session_server(ne_session **sess, const char *scheme,\n                               const char *host, unsigned int fakeport,\n                               server_fn fn, void *userdata)\n{\n    return fakeproxied_multi_session_server(1, sess, scheme, host, fakeport,\n                                            fn, userdata);\n}\n\nint fakeproxied_multi_session_server(int count,\n                                     ne_session **sess, const char *scheme,\n                                     const char *host, unsigned int fakeport,\n                                     server_fn fn, void *userdata)\n{\n    ne_inet_addr *addr;\n    const ne_inet_addr *alist[1];\n    \n    CALL(new_spawn_server2(count, fn, userdata, &addr, &session_port));\n\n    NE_DEBUG(NE_DBG_HTTP, \"test: Using fake proxied '%s' session for %s using port %u.\\n\",\n             scheme, host, session_port);\n    \n    alist[0] = addr;\n\n    *sess = ne_session_create(scheme, host, fakeport);\n\n    ne_set_addrlist2(*sess, session_port, alist, 1);\n\n    ne_hook_destroy_session(*sess, fakesess_destroy, addr);\n\n    return OK;\n}\n\nint socksproxied_session_server(ne_session **sess, struct socks_server *srv,\n                                const char *hostname, unsigned int port,\n                                server_fn server, void *userdata)\n{\n    srv->server = server;\n    srv->userdata = userdata;\n\n    CALL(new_spawn_server(1, socks_server, srv, &session_port));\n    *sess = ne_session_create(\"http\", hostname, port);\n    ne_session_socks_proxy(*sess, srv->version, localhost_session_host(), session_port,\n                           srv->username, srv->password);\n    return OK;\n}\n\nint make_session(ne_session **sess, server_fn fn, void *ud)\n{\n    return session_server(sess, fn, ud);\n}\n\nint file_to_buffer(const char *filename, ne_buffer *buf)\n{\n    char buffer[BUFSIZ];\n    int fd;\n    ssize_t n;\n    \n    fd = open(filename, O_RDONLY);\n    ONV(fd < 0, (\"could not open file %s\", filename));\n\n    while ((n = read(fd, buffer, BUFSIZ)) > 0) {\n\tne_buffer_append(buf, buffer, n);\n    }\n\n    close(fd);\n    \n    return 0;\n}\n\n#define sornull(s_) (s_ ? s_ : \"[null]\")\n\nvoid sess_notifier(void *userdata, ne_session_status status,\n                   const ne_session_status_info *info)\n{\n    ne_buffer *buf = userdata;\n    char scratch[512];\n\n    switch (status) {\n    case ne_status_lookup:\n        ne_buffer_concat(buf, \"lookup(\", sornull(info->lu.hostname), \")-\", NULL);\n        break;\n    case ne_status_connecting:\n        ne_iaddr_print(info->ci.address, scratch, sizeof scratch);\n        ne_buffer_concat(buf, \"connecting(\", sornull(info->lu.hostname),\n                         \",\", scratch, \")-\", NULL);\n        break;\n    case ne_status_disconnected:\n        ne_buffer_czappend(buf, \"dis\");\n        /* fallthrough */\n    case ne_status_connected:\n        ne_buffer_concat(buf, \"connected(\", sornull(info->cd.hostname),\n                         \")-\", NULL);\n        break;\n    case ne_status_sending:\n    case ne_status_recving:\n        ne_snprintf(scratch, sizeof scratch,\n                    \"%\" NE_FMT_NE_OFF_T \",%\" NE_FMT_NE_OFF_T,\n                    info->sr.progress, info->sr.total);\n        ne_buffer_concat(buf,\n                         status == ne_status_sending ? \"send\" : \"recv\",\n                         \"(\", scratch, \")-\", NULL);\n        break;\n    case ne_status_handshake:\n        ne_buffer_snprintf(buf, 256,\n                           \"handshake(%s, %s)-\",\n                           ne_ssl_proto_name(info->hs.protocol),\n                           info->hs.ciphersuite ?\n                           info->hs.ciphersuite : \"[none]\");\n        break;\n    default:\n        ne_buffer_czappend(buf, \"bork!\");\n        break;\n    }\n\n    NE_DEBUG(NE_DBG_HTTP, \"notifier %d => %s\\n\",\n             status, buf->data);\n}\n\n#undef sornull\n"
  },
  {
    "path": "test/utils.h",
    "content": "/* \n   neon-specific test utils\n   Copyright (C) 2001-2009, Joe Orton <joe@manyfish.co.uk>\n\n   This program is free software; you can redistribute it and/or modify\n   it under the terms of the GNU General Public License as published by\n   the Free Software Foundation; either version 2 of the License, or\n   (at your option) any later version.\n  \n   This program is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU General Public License for more details.\n  \n   You should have received a copy of the GNU General Public License\n   along with this program; if not, write to the Free Software\n   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\n*/\n\n#ifndef UTILS_H\n#define UTILS_H 1\n\n#include \"ne_request.h\"\n\n#include \"child.h\"\n\n#define ONREQ(x) do { int _ret = (x); if (_ret) { t_context(\"line %d: HTTP error:\\n%s\", __LINE__, ne_get_error(sess)); return FAIL; } } while (0);\n\nint single_serve_string(ne_socket *s, void *userdata);\n\nint serve_response(ne_socket *s, const char *response);\n\nstruct many_serve_args {\n    int count;\n    const char *str;\n};\n\n/* Serves args->str response args->count times down a single\n * connection. */\nint many_serve_string(ne_socket *s, void *userdata);\n\n/* Run a request using URI on the session. */\nint any_request(ne_session *sess, const char *uri);\n\n/* Run a request using URI on the session; fail on a non-2xx response.\n */\nint any_2xx_request(ne_session *sess, const char *uri);\n\n/* As above but with a request body. */\nint any_2xx_request_body(ne_session *sess, const char *uri);\n\n/* As any_2xx_request but with a specified method. */\nint any_2xx_request_method(ne_session *sess, const char *method,\n                           const char *uri);\n\n/* makes *session, spawns server which will run 'fn(userdata,\n * socket)'.  sets error context if returns non-zero, i.e use like:\n * CALL(make_session(...)); */\nint make_session(ne_session **sess, server_fn fn, void *userdata);\n\n/* Returns hostname used for make_session(). */\nconst char *get_session_host(void);\n\nunsigned int get_session_port(void);\n\n/* Server which sleeps for 10 seconds then closes the socket. */\nint sleepy_server(ne_socket *sock, void *userdata);\n\nstruct string {\n    char *data;\n    size_t len;\n};\n\nstruct double_serve_args {\n    struct string first, second;\n};\n\n/* Serve a struct string. */\nint serve_sstring(ne_socket *sock, void *ud);\n\n/* Serve a ne_buffer *. */\nint serve_buffer(ne_socket *sock, void *ud);\n\n/* Discards an HTTP request, serves response ->first, discards another\n * HTTP request, then serves response ->second. */\nint double_serve_sstring(ne_socket *s, void *userdata);\n\n/* Serve a struct string slowly. */\nint serve_sstring_slowly(ne_socket *sock, void *ud);\n\nstruct infinite {\n    const char *header, *repeat;\n};\n\n/* Pass a \"struct infinite *\" as userdata, this function sends\n * ->header and then loops sending ->repeat forever. */\nint serve_infinite(ne_socket *sock, void *ud);\n\n/* SOCKS server stuff. */\nstruct socks_server {\n    enum ne_sock_sversion version;\n    enum socks_failure {\n        fail_none = 0,\n        fail_init_vers,\n        fail_init_close,\n        fail_init_trunc,\n        fail_no_auth,\n        fail_bogus_auth, \n        fail_auth_close, \n        fail_auth_denied \n    } failure;\n    unsigned int expect_port;\n    ne_inet_addr *expect_addr;\n    const char *expect_fqdn;\n    const char *username;\n    const char *password;\n    int say_hello;\n    server_fn server;\n    void *userdata;\n};\n\nint socks_server(ne_socket *sock, void *userdata);\n\nint full_write(ne_socket *sock, const char *data, size_t len);\n    \n/* Create a session with server process running fn(userdata).  Sets\n * test suite error on failure; initializes *sess with a new session\n * on success.  Uses an unspecified hostname/port for the server. */\nint session_server(ne_session **sess, server_fn fn, void *userdata);\n\n/* Create a session for scheme with server process running count\n * multiple iterations fn(userdata).  Sets test suite error on\n * failure; initializes *sess with a new session on success.  Uses an\n * unspecified hostname/port for the server. */\nint multi_session_server(ne_session **sess, const char *scheme,\n                         int count, server_fn fn, void *userdata);\n\n/* Create a session with server process running fn(userdata).  Sets\n * test suite error on failure; initializes *sess with a new session\n * on success.  Uses an unspecified hostname/port for the server;\n * session is created as if using origin 'host:fakeport' via HTTP\n * proxy to spawned server.  */\nint proxied_session_server(ne_session **sess, const char *scheme,\n                           const char *host, unsigned int fakeport,\n                           server_fn fn, void *userdata);\n\nint proxied_multi_session_server(int count, ne_session **sess,\n                                 const char *scheme, const char *host,\n                                 unsigned int fakeport,\n                                 server_fn fn, void *userdata);\n\n/* As per proxied_session_server, but uses a \"fake\" (direct) TCP proxy\n * rather than an HTTP proxy. */\nint fakeproxied_session_server(ne_session **sess, const char *scheme,\n                               const char *host, unsigned int fakeport,\n                               server_fn fn, void *userdata);\n\n/* As per fakeproxied_session_server, but also takes an iteration\n * count. */\nint fakeproxied_multi_session_server(int count,\n                                     ne_session **sess, const char *scheme,\n                                     const char *host, unsigned int fakeport,\n                                     server_fn fn, void *userdata);\n\nint socksproxied_session_server(ne_session **sess, struct socks_server *srv,\n                                const char *hostname, unsigned int port,\n                                server_fn server, void *userdata);\n\n/* Read contents of file 'filename' into buffer 'buf'. */\nint file_to_buffer(const char *filename, ne_buffer *buf);\n\n/* Notifier callback which serializes notifier invocations.\n * ne_buffer * must be passed as userdata. */\nvoid sess_notifier(void *userdata, ne_session_status status,\n                   const ne_session_status_info *info);\n\n#define MULTI_207(x) \"HTTP/1.0 207 Foo\\r\\nContent-Type: text/xml\\r\\nConnection: close\\r\\n\\r\\n\" \\\n\"<?xml version='1.0'?>\\r\\n\" \\\n\"<D:multistatus xmlns:D='DAV:'>\" x \"</D:multistatus>\"\n#define RESP_207(href, x) \"<D:response><D:href>\" href \"</D:href>\" x \\\n\"</D:response>\"\n#define PSTAT_207(x) \"<D:propstat>\" x \"</D:propstat>\"\n#define STAT_207(s) \"<D:status>HTTP/1.1 \" s \"</D:status>\"\n#define DESCR_207(d) \"<D:responsedescription>\" d \"</D:responsedescription>\"\n#define DESCR_REM \"The end of the world, as we know it\"\n\n#define PROPS_207(x) \"<D:prop>\" x \"</D:prop>\"\n#define APROP_207(n, c) \"<D:\" n \">\" c \"</D:\" n \">\"\n\n#endif /* UTILS_H */\n"
  },
  {
    "path": "test/xml.c",
    "content": "/* \n   neon test suite\n   Copyright (C) 2002-2007, Joe Orton <joe@manyfish.co.uk>\n\n   This program is free software; you can redistribute it and/or modify\n   it under the terms of the GNU General Public License as published by\n   the Free Software Foundation; either version 2 of the License, or\n   (at your option) any later version.\n  \n   This program is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU General Public License for more details.\n  \n   You should have received a copy of the GNU General Public License\n   along with this program; if not, write to the Free Software\n   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\n*/\n\n#include \"config.h\"\n\n#include <sys/types.h>\n\n#ifdef HAVE_STDLIB_H\n#include <stdlib.h>\n#endif\n#ifdef HAVE_UNISTD_H\n#include <unistd.h>\n#endif\n\n#include \"ne_xml.h\"\n\n#include \"tests.h\"\n#include \"child.h\"\n#include \"utils.h\"\n\n#define ABORT (-42) /* magic code for abort handlers */\n\n#define EVAL_DEFAULT \"eval-xmlns-default\"\n#define EVAL_SPECIFIC \"eval-xmlns-specific-\"\n\nstruct context {\n    ne_buffer *buf;\n    ne_xml_parser *parser;\n};\n\n/* A set of SAX handlers which serialize SAX events back into a \n * pseudo-XML-like string. */\nstatic int startelm(void *userdata, int state,\n                    const char *nspace, const char *name,\n\t\t    const char **atts)\n{\n    struct context *ctx = userdata;\n    ne_buffer *buf = ctx->buf;\n    int n;\n\n    if (strcmp(name, \"decline\") == 0)\n        return NE_XML_DECLINE;\n\n    if (strcmp(name, EVAL_DEFAULT) == 0) {\n        const char *val = ne_xml_resolve_nspace(ctx->parser, NULL, 0);\n\n        ne_buffer_concat(ctx->buf, EVAL_DEFAULT \"=[\", val, \"]\", NULL);\n        return NE_XML_DECLINE;\n    }\n    else if (strncmp(name, EVAL_SPECIFIC, strlen(EVAL_SPECIFIC)) == 0) {\n        const char *which = name + strlen(EVAL_SPECIFIC);\n        const char *r = ne_xml_resolve_nspace(ctx->parser, which, strlen(which));\n        \n        ne_buffer_concat(ctx->buf, name, \"=[\", r, \"]\", NULL);\n        return NE_XML_DECLINE;\n    }\n\n    ne_buffer_concat(buf, \"<\", \"{\", nspace, \"}\", name, NULL);\n    for (n = 0; atts && atts[n] != NULL; n+=2) {\n\tne_buffer_concat(buf, \" \", atts[n], \"='\", atts[n+1], \"'\", NULL);\n    }\n    ne_buffer_zappend(buf, \">\");\n\n    return state + 1;\n}\n\nstatic int chardata(void *userdata, int state, const char *cdata, size_t len)\n{\n    struct context *ctx = userdata;\n    ne_buffer_append(ctx->buf, cdata, len);\n    return strncmp(cdata, \"!ABORT!\", len) == 0 ? ABORT : NE_XML_DECLINE;\n}\n\nstatic int endelm(void *userdata, int state,\n                  const char *nspace, const char *name)\n{\n    struct context *ctx = userdata;\n    ne_buffer_concat(ctx->buf, \"</{\", nspace, \"}\", name, \">\", NULL);\n    return 0;\n}\n\n/* A set of SAX handlers which do as above, but change some element\n * names; used to check nested SAX handling is working properly.  */\nstatic int startelm_xform(void *userdata, int state,\n                          const char *nspace, const char *name,\n                          const char **atts)\n{\n    if (strcmp(nspace, \"two\") == 0)\n        return startelm(userdata, state, nspace, \"xform\", atts);\n    else\n        return NE_XML_DECLINE;\n}\n\nstatic int endelm_xform(void *userdata, int state,\n                        const char *nspace, const char *name)\n{\n    if (strcmp(nspace, \"two\") == 0)\n        return endelm(userdata, state, nspace, \"xform\");\n    else\n        return NE_XML_DECLINE;\n}\n\n/* A set of SAX handlers which verify that state handling is working\n * correctly. */\nstatic int startelm_state(void *userdata, int parent,\n                          const char *nspace, const char *name,\n                          const char **atts)\n{\n    struct context *ctx = userdata;\n    int n;\n\n    if (strcmp(nspace, \"state\") != 0)\n        return NE_XML_DECLINE;\n\n    for (n = 0; atts[n]; n += 2) {\n        if (strcmp(atts[n], \"parent\") == 0) {\n            int expected = atoi(atts[n+1]);\n            \n            if (expected != parent) {\n                char err[50];\n                sprintf(err, \"parent state of %s was %d not %d\", name, parent, \n                    expected);\n                ne_buffer_zappend(ctx->buf, err);\n            }\n        }\n    }\n\n    return atoi(name+1);    \n}\n\nstatic int endelm_state(void *userdata, int state,\n                        const char *nspace, const char *name)\n{\n    int expected = atoi(name + 1);\n    struct context *ctx = userdata;\n    \n    if (state != expected)\n        ne_buffer_concat(ctx->buf, \"wrong state in endelm of \", name, NULL);\n    \n    return 0;\n}\n\n/* A set of SAX handlers which verify that abort handling is working\n * correctly. */\nstatic int startelm_abort(void *userdata, int parent,\n                          const char *nspace, const char *name,\n                          const char **atts)\n{\n    struct context *ctx = userdata;\n\n    if (strcmp(name, \"abort-start\") == 0) {\n        ne_buffer_zappend(ctx->buf, \"ABORT\");\n        return ABORT;\n    } else\n        return startelm(ctx, parent, nspace, name, atts);\n}\n\nstatic int endelm_abort(void *userdata, int state,\n                        const char *nspace, const char *name)\n{\n    struct context *ctx = userdata;\n\n    if (strcmp(name, \"abort-end\") == 0) {\n        ne_buffer_zappend(ctx->buf, \"ABORT\");\n        return ABORT;\n    } else\n        return 0;\n}\n\n/* Test mode for parse_match: */\nenum match_type {\n    match_valid = 0, /* test that the parse succeeds */\n    match_invalid, /* test that the parse fails */\n    match_nohands, /* test with no handlers registered */\n    match_encoding, /* test whether the encoding is equal to the result string */\n    match_chunked /* parse the document one byte at a time */\n};\n\nstatic int parse_match(const char *doc, const char *result, \n                       enum match_type t, const char *encoding)\n{\n    const char *origdoc = doc;\n    ne_xml_parser *p = ne_xml_create();\n    ne_buffer *buf = ne_buffer_create();\n    int ret;\n    struct context ctx;\n    \n    if (encoding) {\n        ret = ne_xml_set_encoding(p, encoding);\n        ONV(ret, (\"ne_xml_set_encoding for %s failed with %d\", encoding, ret));\n    }\n\n    ctx.buf = buf;\n    ctx.parser = p;\n\n    if (t == match_invalid)\n        ne_xml_push_handler(p, startelm_abort, chardata, endelm_abort, &ctx);\n    if (t != match_encoding && t != match_nohands) {\n        ne_xml_push_handler(p, startelm_state, NULL, endelm_state, &ctx);\n        ne_xml_push_handler(p, startelm, chardata, endelm, &ctx);\n        ne_xml_push_handler(p, startelm_xform, chardata, endelm_xform, &ctx);\n    }\n\n    if (t == match_chunked) {\n        do {\n            ret = ne_xml_parse(p, doc++, 1);\n        } while (ret == 0 && *doc);\n    } else {\n        ret = ne_xml_parse(p, doc, strlen(doc));\n    }\n\n    if (ret == 0) {\n        ne_xml_parse(p, \"\", 0);\n    }\n\n    ONV(ret != ne_xml_failed(p), \n        (\"'%s': ne_xml_failed gave %d not %d\", origdoc, ne_xml_failed(p), ret));\n\n    if (t == match_invalid)\n        ONV(ret != ABORT, \n            (\"for '%s': parse got %d not abort failure: %s\", origdoc, ret, \n             buf->data));\n    else\n        ONV(ret, (\"for '%s': parse failed: %s\", origdoc, ne_xml_get_error(p)));\n    \n    if (t == match_encoding) {\n        const char *enc = ne_xml_doc_encoding(p);\n\n        ONV(enc == NULL || strcmp(enc, result),\n            (\"for '%s': encoding was `%s' not `%s'\", origdoc, enc, result));\n    }\n    else if (t == match_valid || t == match_chunked) {\n        ONV(strcmp(result, buf->data),\n            (\"for '%s': result mismatch: %s not %s\", origdoc, buf->data, \n             result));\n    }\n\n    ne_xml_destroy(p);\n    ne_buffer_destroy(buf);\n\n    return OK;\n}\n\n#define ISO_FOOBAR \"f\\xd8\\xd8\" \"b\\xe1\" \"r\"\n\nstatic int matches(void)\n{\n#define PFX \"<?xml version='1.0' encoding='utf-8'?>\\r\\n\"\n#define E(ns, n) \"<{\" ns \"}\" n \"></{\" ns \"}\" n \">\"\n    static const struct {\n\tconst char *in, *out;\n        enum match_type invalid;\n        const char *encoding;\n    } ms[] = {\n        \n        /*** Simplest tests ***/\n\t{ PFX \"<hello/>\", \"<{}hello></{}hello>\"},\n\t{ PFX \"<hello foo='bar'/>\",\n\t  \"<{}hello foo='bar'></{}hello>\"},\n\n\t/*** Tests for character data handling. ***/\n\t{ PFX \"<hello> world</hello>\", \"<{}hello> world</{}hello>\"},\n\t/* test for cdata between elements. */\n\t{ PFX \"<hello>\\r\\n<wide>  world</wide></hello>\",\n\t  \"<{}hello>\\n<{}wide>  world</{}wide></{}hello>\"},\n\n        /* UTF-8 XML Byte Order Mark */\n        { \"\\xEF\\xBB\\xBF\" PFX \"<hello/>\", \"<{}hello></{}hello>\" },\n        /* UTF-8 XML Byte Order Mark */\n        { \"\\xEF\\xBB\\xBF\" PFX \"<hello/>\", \"<{}hello></{}hello>\", match_chunked },\n        /* UTF-8 XML Byte Order Mark sans prolog */\n        { \"\\xEF\\xBB\\xBF\" \"<hello/>\", \"<{}hello></{}hello>\" },\n\n\t/*** Tests for namespace handling. ***/\n#define NSA \"xmlns:foo='bar'\"\n\t{ PFX \"<foo:widget \" NSA \"/>\", \n\t  \"<{bar}widget \" NSA \">\"\n\t  \"</{bar}widget>\" },\n\t/* inherited namespace expansion. */\n\t{ PFX \"<widget \" NSA \"><foo:norman/></widget>\",\n\t  \"<{}widget \" NSA \">\" E(\"bar\", \"norman\") \"</{}widget>\"},\n\t{ PFX \"<widget \" NSA \" xmlns:abc='def' xmlns:g='z'>\"\n          \"<foo:norman/></widget>\",\n\t  \"<{}widget \" NSA \" xmlns:abc='def' xmlns:g='z'>\" \n          E(\"bar\", \"norman\") \"</{}widget>\"},\n\t/* empty namespace default takes precedence. */\n\t{ PFX \"<widget xmlns='foo'><smidgen xmlns=''><norman/>\"\n\t  \"</smidgen></widget>\",\n\t  \"<{foo}widget xmlns='foo'><{}smidgen xmlns=''>\" \n\t  E(\"\", \"norman\") \n\t  \"</{}smidgen></{foo}widget>\" },\n        /* inherited empty namespace default */\n        { PFX \"<bar xmlns='foo'><grok xmlns=''><fish/></grok></bar>\",\n          \"<{foo}bar xmlns='foo'><{}grok xmlns=''>\" \n          E(\"\", \"fish\") \"</{}grok></{foo}bar>\" },\n\n\t/* regression test for neon <= 0.23.5 with libxml2, where the\n\t * \"dereference entities\" flag was not set by default. */\n\t{ PFX \"<widget foo=\\\"no&amp;body\\\"/>\",\n\t  \"<{}widget foo='no&body'></{}widget>\" },\n\t{ PFX \"<widget foo=\\\"no&#x20;body\\\"/>\",\n\t  \"<{}widget foo='no body'></{}widget>\" },\n\n        /* tests for declined branches */\n        { PFX \"<hello><decline>fish</decline>\"\n          \"<world><decline/>yes</world>goodbye<decline/></hello>\",\n          \"<{}hello><{}world>yes</{}world>goodbye</{}hello>\" },\n        { PFX \n          \"<hello><decline><nested>fish</nested>bar</decline><fish/></hello>\",\n          \"<{}hello>\" E(\"\", \"fish\") \"</{}hello>\" },\n        /* tests for nested SAX handlers */\n        { PFX \"<hello xmlns='two'><decline/></hello>\",\n          \"<{two}hello xmlns='two'>\" E(\"two\", \"xform\") \"</{two}hello>\"},\n\n        /* test for nspace resolution. */\n        { PFX \"<hello xmlns='fish'><\" EVAL_DEFAULT \"/></hello>\",\n          \"<{fish}hello xmlns='fish'>\" EVAL_DEFAULT \"=[fish]\" \"</{fish}hello>\" },\n        { PFX \"<hello><\" EVAL_DEFAULT \"/></hello>\",\n          \"<{}hello>\" EVAL_DEFAULT \"=[]</{}hello>\" },\n\n        { PFX \"<hello xmlns:foo='bar'><\" EVAL_SPECIFIC \"foo/></hello>\",\n          \"<{}hello xmlns:foo='bar'>\" EVAL_SPECIFIC \"foo=[bar]</{}hello>\" },\n\n        /* tests for state handling */\n        { PFX \"<a55 xmlns='state'/>\", \"\" },\n        { PFX \"<a777 xmlns='state' parent='0'/>\", \"\" },\n        { PFX \"<a99 xmlns='state'><f77 parent='99'/>blah</a99>\", \"\" },\n\n        /* tests for abort handling */\n        { PFX \"<hello><merry><abort-start/></merry></hello>\",\n          \"<{}hello><{}merry>ABORT\", match_invalid },\n        { PFX \"<hello><merry><abort-end/>fish</merry></hello>\",\n          \"<{}hello><{}merry><{}abort-end>ABORT\", match_invalid },\n        { PFX \"<hello>!ABORT!</hello>\", \"<{}hello>!ABORT!\", match_invalid },\n        { PFX \"<hello>!ABORT!<foo/></hello>\", \"<{}hello>!ABORT!\", match_invalid },\n\n        /* tests for encodings */\n        { \"<?xml version='1.0' encoding='ISO-8859-1'?><hello/>\",\n          \"ISO-8859-1\", match_encoding },\n\n        { \"<?xml version='1.0' encoding='UTF-8'?><hello/>\",\n          \"UTF-8\", match_encoding },\n\n        { \"<?xml version='1.0'?><hello>\" ISO_FOOBAR \"</hello>\",\n          \"<{}hello>fØØbár</{}hello>\", match_valid, \"ISO-8859-1\" },\n\n        /* test that parse is valid even with no handlers registered. */\n        { PFX \"<hello><old>world</old></hello>\", \"\", match_nohands },\n\n        /* regression test for prefix matching bug fixed in 0.18.0 */\n#define THENS \"xmlns:d='foo' xmlns:dd='bar'\"\n        { PFX \"<d:hello \" THENS \"/>\",\n          \"<{foo}hello \" THENS \"></{foo}hello>\" },\n\n        /**** end of list ****/ { NULL, NULL }\n    };\n    int n;\n\n    for (n = 0; ms[n].in != NULL; n++) {\n\tCALL(parse_match(ms[n].in, ms[n].out, ms[n].invalid, ms[n].encoding));\n    }\n\n    return OK;\n}\n\nstatic int mapping(void)\n{\n    static const struct ne_xml_idmap map[] = {\n        { \"fee\", \"bar\", 1 },\n        { \"foo\", \"bar\", 2 },\n        { \"bar\", \"foo\", 3 },\n        { \"\", \"bob\", 4 },\n        { \"balloon\", \"buffoon\", 5},\n        { NULL, NULL, 0}\n    };\n    int n;\n\n    for (n = 0; map[n].id; n++) {\n        int id = ne_xml_mapid(map, NE_XML_MAPLEN(map) - 1,\n                              map[n].nspace, map[n].name);\n        ONV(id != map[n].id, (\"mapped to id %d not %d\", id, map[n].id));\n    }\n\n    n = ne_xml_mapid(map, NE_XML_MAPLEN(map) - 1, \"no-such\", \"element\");\n    ONV(n != 0, (\"unknown element got id %d not zero\", n));\n\n    return OK;\n}\n\n/* Test for some parse failures */\nstatic int fail_parse(void)\n{\n    static const char *docs[] = {\n        \"foo\",\n        PFX \"<bar:foo/>\",\n        /* malformed namespace declarations */\n        PFX \"<foo xmlns:D=''/>\",\n        PFX \"<foo xmlns:='fish'/>\",\n        PFX \"<foo xmlns:.bar='fish'/>\",\n        PFX \"<foo xmlns:-bar='fish'/>\",\n        PFX \"<foo xmlns:0bar='fish'/>\",\n        PFX \"<fee xmlns:8baz='bar'/>\",\n\n        /* element names which are not valid QNames. */\n        PFX \"<foo: xmlns:foo='bar'/>\",\n        PFX \"<:fee/>\",\n        PFX \"<0fish/>\",\n        PFX \"<foo:0fish xmlns:foo='bar'/>\",\n        PFX \"<foo:9fish xmlns:foo='bar'/>\",\n        PFX \"<foo:-fish xmlns:foo='bar'/>\",\n        PFX \"<foo:.fish xmlns:foo='bar'/>\",\n\n#if 0 /* currently disabled to allow SVN to work */\n        PFX \"<foo:bar:baz xmlns:foo='bar'/>\",\n        PFX \"<fee xmlns:baz:bar='bar'/>\",\n        PFX \"<fee xmlns::bar='bar'/>\",\n        PFX \"<foo::fish xmlns:foo='bar'/>\",\n#endif\n\n        /* These are tests of XML parser itself really... */\n        /* 2-byte encoding of '.': */\n        PFX \"<foo>\" \"\\x2F\\xC0\\xAE\\x2E\\x2F\" \"</foo>\",\n        /* 3-byte encoding of '.': */\n        PFX \"<foo>\" \"\\x2F\\xE0\\x80\\xAE\\x2E\\x2F\" \"</foo>\",\n        /* 4-byte encoding of '.': */\n        PFX \"<foo>\" \"\\x2F\\xF0\\x80\\x80\\xAE\\x2E\\x2F\" \"</foo>\",\n        /* 5-byte encoding of '.': */\n        PFX \"<foo>\" \"\\x2F\\xF8\\x80\\x80\\x80\\xAE\\x2E\\x2F\" \"</foo>\",\n        /* 6-byte encoding of '.': */\n        PFX \"<foo>\" \"\\x2F\\xFC\\x80\\x80\\x80\\x80\\xAE\\x2E\\x2F\" \"</foo>\",\n        /* two-byte encoding of '<' must not be parsed as a '<': */\n        PFX \"\\xC0\\xBC\" \"foo></foo>\",\n\n        /* Invalid UTF-8 XML Byte Order Marks */\n        \"\\xEF\\xBB\" PFX \"<hello/>\",\n        \"\\xEF\" PFX \"<hello/>\",\n\n\"<?xml version=\\\"1.0\\\"?>\\\n<!DOCTYPE billion [\\\n<!ELEMENT billion (#PCDATA)>\\\n<!ENTITY laugh0 \\\"ha\\\">\\\n<!ENTITY laugh1 \\\"&laugh0;&laugh0;\\\">\\\n<!ENTITY laugh2 \\\"&laugh1;&laugh1;\\\">\\\n<!ENTITY laugh3 \\\"&laugh2;&laugh2;\\\">\\\n<!ENTITY laugh4 \\\"&laugh3;&laugh3;\\\">\\\n<!ENTITY laugh5 \\\"&laugh4;&laugh4;\\\">\\\n<!ENTITY laugh6 \\\"&laugh5;&laugh5;\\\">\\\n<!ENTITY laugh7 \\\"&laugh6;&laugh6;\\\">\\\n<!ENTITY laugh8 \\\"&laugh7;&laugh7;\\\">\\\n<!ENTITY laugh9 \\\"&laugh8;&laugh8;\\\">\\\n<!ENTITY laugh10 \\\"&laugh9;&laugh9;\\\">\\\n<!ENTITY laugh11 \\\"&laugh10;&laugh10;\\\">\\\n<!ENTITY laugh12 \\\"&laugh11;&laugh11;\\\">\\\n<!ENTITY laugh13 \\\"&laugh12;&laugh12;\\\">\\\n<!ENTITY laugh14 \\\"&laugh13;&laugh13;\\\">\\\n<!ENTITY laugh15 \\\"&laugh14;&laugh14;\\\">\\\n<!ENTITY laugh16 \\\"&laugh15;&laugh15;\\\">\\\n<!ENTITY laugh17 \\\"&laugh16;&laugh16;\\\">\\\n<!ENTITY laugh18 \\\"&laugh17;&laugh17;\\\">\\\n<!ENTITY laugh19 \\\"&laugh18;&laugh18;\\\">\\\n<!ENTITY laugh20 \\\"&laugh19;&laugh19;\\\">\\\n<!ENTITY laugh21 \\\"&laugh20;&laugh20;\\\">\\\n<!ENTITY laugh22 \\\"&laugh21;&laugh21;\\\">\\\n<!ENTITY laugh23 \\\"&laugh22;&laugh22;\\\">\\\n<!ENTITY laugh24 \\\"&laugh23;&laugh23;\\\">\\\n<!ENTITY laugh25 \\\"&laugh24;&laugh24;\\\">\\\n<!ENTITY laugh26 \\\"&laugh25;&laugh25;\\\">\\\n<!ENTITY laugh27 \\\"&laugh26;&laugh26;\\\">\\\n<!ENTITY laugh28 \\\"&laugh27;&laugh27;\\\">\\\n<!ENTITY laugh29 \\\"&laugh28;&laugh28;\\\">\\\n<!ENTITY laugh30 \\\"&laugh29;&laugh29;\\\">\\\n]>\\\n<billion>&laugh30;</billion>\\\n\",\n\n        NULL\n    };\n    int n;\n\n    for (n = 0; docs[n]; n++) {\n        ne_xml_parser *p = ne_xml_create();\n        const char *err;\n\n        ne_xml_parse(p, docs[n], strlen(docs[n]));\n        ne_xml_parse(p, \"\", 0);\n        ONV(ne_xml_failed(p) <= 0, \n            (\"`%s' did not get positive parse error\", docs[n]));\n\n        err = ne_xml_get_error(p);\n        NE_DEBUG(NE_DBG_HTTP, \"Parse error for '%s': %s\\n\", docs[n], err);\n        ONV(strstr(err, \"parse error\") == NULL\n            && strstr(err, \"Invalid Byte Order Mark\") == NULL,\n            (\"bad error %s\", err));\n        \n        ne_xml_destroy(p);\n    }\n\n    return OK;\n}\n\nstatic int check_attrib(ne_xml_parser *p, const char **atts, \n                        const char *nspace, const char *name,\n                        const char *value)\n{\n    const char *act = ne_xml_get_attr(p, atts, nspace, name);\n    char err[50];\n    int ret = 0;\n\n    if (value == NULL) {\n        if (act != NULL) {\n            sprintf(err, \"attribute %s was set to %s\", name, act);\n            ret = NE_XML_ABORT;\n        }\n    } else {\n        if (act == NULL) {\n            sprintf(err, \"attribute %s not found\", name);\n            ret = NE_XML_ABORT;\n        } else if (strcmp(act, value) != 0) {\n            sprintf(err, \"attribute %s was %s not %s\", name, act, value);\n            ret = NE_XML_ABORT;\n        }\n    }\n    if (ret == NE_XML_ABORT) ne_xml_set_error(p, err);\n    return ret;\n}\n\nstatic int startelm_attrib(void *userdata, int state,\n                           const char *nspace, const char *name,\n                           const char **atts)\n{\n    ne_xml_parser *p = userdata;\n    \n    if (strcmp(name, \"hello\") == 0) {\n        CALL(check_attrib(p, atts, NULL, \"first\", \"second\"));\n        CALL(check_attrib(p, atts, NULL, \"third\", \"\"));\n        CALL(check_attrib(p, atts, \"garth\", \"bar\", \"asda\"));\n        CALL(check_attrib(p, atts, \"giraffe\", \"bar\", NULL));\n        CALL(check_attrib(p, atts, \"hot\", \"dog\", NULL));\n        CALL(check_attrib(p, atts, NULL, \"nonesuch\", NULL));\n    } else if (strcmp(name, \"goodbye\") == 0) {\n        if (atts[0] != NULL) {\n            ne_xml_set_error(p, \"non-empty attrib array\");\n            return 1;\n        }\n    }\n\n    return 1;\n}\n\nstatic int attributes(void)\n{\n    ne_xml_parser *p = ne_xml_create();\n    static const char doc[] = PFX\n        \"<hello xmlns:foo='garth' first='second' third='' \"\n        \"foo:bar='asda' goof:bar='jar'><goodbye/></hello>\";\n\n    ne_xml_push_handler(p, startelm_attrib, NULL, NULL, p);\n\n    ne_xml_parse_v(p, doc, strlen(doc));\n\n    ONV(ne_xml_failed(p), (\"parse error: %s\", ne_xml_get_error(p)));\n\n    ne_xml_destroy(p);\n    return OK;\n}\n\n/* Test for the get/set error interface */\nstatic int errors(void)\n{\n    ne_xml_parser *p = ne_xml_create();\n    const char *err;\n    \n    ONV(strcmp(ne_xml_get_error(p), \"Unknown error\") != 0,\n        (\"initial error string unspecified\"));\n\n    ne_xml_set_error(p, \"Fish food\");\n    err = ne_xml_get_error(p);\n    \n    ONV(strcmp(err, \"Fish food\"), (\"wrong error %s!\", err));\n\n    ne_xml_destroy(p);\n    return 0;\n}\n\nne_test tests[] = {\n    T(matches),\n    T(mapping),\n    T(fail_parse),\n    T(attributes),\n    T(errors),\n    T(NULL)\n};\n\n"
  },
  {
    "path": "test/xmlreq.c",
    "content": "/* \n   Test cases for the ne_xmlreq.h interface.\n   Copyright (C) 2005-2006, Joe Orton <joe@manyfish.co.uk>\n\n   This program is free software; you can redistribute it and/or modify\n   it under the terms of the GNU General Public License as published by\n   the Free Software Foundation; either version 2 of the License, or\n   (at your option) any later version.\n  \n   This program is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n   GNU General Public License for more details.\n  \n   You should have received a copy of the GNU General Public License\n   along with this program; if not, write to the Free Software\n   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n\n*/\n\n#include \"config.h\"\n\n#include <sys/types.h>\n\n#ifdef HAVE_STDLIB_H\n#include <stdlib.h>\n#endif\n#ifdef HAVE_UNISTD_H\n#include <unistd.h>\n#endif\n\n#include \"ne_xmlreq.h\"\n\n#include \"tests.h\"\n#include \"utils.h\"\n\n/* Dummy start_element callback; takes int * userdata and toggles the\n * pointed-to int iff the root element has name \"hello\".  Accepts all\n * elements. */\nstatic int startelm(void *userdata, int state,\n                    const char *nspace, const char *name,\n\t\t    const char **atts)\n{\n    int *flag = userdata;\n\n    if (state == NE_XML_STATEROOT && strcmp(name, \"hello\") == 0) {\n        *flag = !*flag;\n    }\n\n    return ++state;\n}\n\nstatic int pc_startelm(void *userdata, int state,\n                    const char *nspace, const char *name,\n\t\t    const char **atts)\n{\n    ne_buffer *buf = userdata;\n    ne_buffer_concat(buf, \"<\", \"{\", nspace, \"}\", name, \">\", NULL);\n    return state + 1;\n}\n\nstatic int pc_chardata(void *userdata, int state, const char *cdata, size_t len)\n{\n    ne_buffer *buf = userdata;\n    ne_buffer_append(buf, cdata, len);\n    return NE_XML_DECLINE;\n}\n\nstatic int parse_for_ctype(const char *ctype, const char *body, size_t len,\n                           const char *output)\n{\n    ne_session *sess;\n    ne_request *req;\n    ne_xml_parser *parser;\n    ne_buffer *buf = ne_buffer_create();\n\n    ne_buffer_concat(buf, \"HTTP/1.1 200 OK\\r\\n\" \"Content-Type: \", ctype, \"\\r\\n\",\n                     \"Connection: close\\r\\n\" \"\\r\\n\", NULL);\n    ne_buffer_append(buf, body, len);\n\n    CALL(make_session(&sess, serve_buffer, buf));\n    \n    req = ne_request_create(sess, \"PARSE\", \"/\");\n    parser = ne_xml_create();\n\n    ne_buffer_clear(buf);\n    ne_xml_push_handler(parser, pc_startelm, pc_chardata, NULL, buf);\n    \n    ONREQ(ne_xml_dispatch_request(req, parser));\n\n    if (output) {\n        ONV(strcmp(buf->data, output),\n            (\"for '%s': result mismatch: %s not %s\", ctype, buf->data,\n             output));\n    }\n\n    ne_buffer_destroy(buf);\n    ne_xml_destroy(parser);\n    ne_request_destroy(req);\n    return destroy_and_wait(sess);\n}\n\n#define ISO_FOOBAR \"f\\xd8\\xd8\" \"b\\xe1\" \"r\"\n#define UTF8_FOOBAR \"fØØbár\"\n\nstatic const unsigned char foobar_utf16_be[] = {\n  0x00, 0x3c, 0x00, 0x3f, 0x00, 0x78, 0x00, 0x6d, 0x00, 0x6c, 0x00, 0x20,\n  0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f,\n  0x00, 0x6e, 0x00, 0x3d, 0x00, 0x27, 0x00, 0x31, 0x00, 0x2e, 0x00, 0x30,\n  0x00, 0x27, 0x00, 0x20, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x63, 0x00, 0x6f,\n  0x00, 0x64, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x3d, 0x00, 0x27,\n  0x00, 0x75, 0x00, 0x74, 0x00, 0x66, 0x00, 0x2d, 0x00, 0x38, 0x00, 0x27,\n  0x00, 0x3f, 0x00, 0x3e, 0x00, 0x0a, 0x00, 0x3c, 0x00, 0x66, 0x00, 0x6f,\n  0x00, 0x6f, 0x00, 0x62, 0x00, 0x61, 0x00, 0x72, 0x00, 0x3e, 0x00, 0x66,\n  0x00, 0xd8, 0x00, 0xd8, 0x00, 0x62, 0x00, 0xe1, 0x00, 0x72, 0x00, 0x3c,\n  0x00, 0x2f, 0x00, 0x66, 0x00, 0x6f, 0x00, 0x6f, 0x00, 0x62, 0x00, 0x61,\n  0x00, 0x72, 0x00, 0x3e, 0x00, 0x0a\n};\n\n#define SL(s_) s_, strlen(s_)\n\nstatic int success(void)\n{\n    static const struct {\n        const char *ctype, *body;\n        size_t len;\n        const char *output;\n    } ts[] = {\n        { \"text/xml\", SL(\"<?xml version='1.0' encoding='UTF-8'?>\\n<hello>foo</hello>\"), \"<{}hello>foo\" },\n        { \"text/xml; charset=ISO-8859-1\", SL(\"<?xml version='1.0'?>\\n<hello>\" ISO_FOOBAR \"</hello>\"),\n          \"<{}hello>\" UTF8_FOOBAR },\n        { \"application/xml; charset=UTF-16BE\", (const char *)foobar_utf16_be, sizeof foobar_utf16_be,\n          \"<{}foobar>\" UTF8_FOOBAR },\n        { \"application/xml\", SL(\"<?xml version='1.0'?><hello/>\") }\n    };\n    unsigned n;\n\n    for (n = 0; n < sizeof(ts)/sizeof(ts[0]); n++)\n        CALL(parse_for_ctype(ts[n].ctype, ts[n].body, ts[n].len, ts[n].output));\n\n    return OK;\n}\n\n#undef SL\n\nstatic int failure(void)\n{\n    ne_session *sess;\n    ne_request *req;\n    ne_xml_parser *parser;\n    \n    CALL(make_session(&sess, single_serve_string, \n                      \"HTTP/1.1 200 OK\\r\\n\"\n                      \"Content-Type: text/xml\\r\\n\"\n                      \"Connection: close\\r\\n\" \"\\r\\n\"\n                      \"<?xml version='1.0' encoding='UTF-8'?>\\n\"\n                      \"<hello>\"));\n    \n    req = ne_request_create(sess, \"PARSE\", \"/\");\n    parser = ne_xml_create();\n    \n    ONN(\"XML parse did not fail\",\n        ne_xml_dispatch_request(req, parser) == NE_OK);\n\n    NE_DEBUG(NE_DBG_HTTP, \"error string: %s\\n\", ne_get_error(sess));\n    \n    ONV(strstr(ne_get_error(sess), \"200 OK\") != NULL,\n        (\"no error string set on parse error: '%s'\", ne_get_error(sess)));\n\n    ne_xml_destroy(parser);\n    ne_request_destroy(req);\n    return destroy_and_wait(sess);\n}\n\nstatic int fail_ctype(void)\n{\n    ne_session *sess;\n    ne_request *req;\n    ne_xml_parser *parser;\n\n    CALL(make_session(&sess, single_serve_string, \n                      \"HTTP/1.1 200 OK\\r\\n\"\n                      \"Content-Type: text/xml; charset=FOOBAR-16\\r\\n\"\n                      \"Connection: close\\r\\n\" \"\\r\\n\"\n                      \"<?xml version='1.0' encoding='UTF-8'?>\\n\"\n                      \"<hello/>\"));\n\n    req = ne_request_create(sess, \"PARSE\", \"/\");\n    parser = ne_xml_create();\n\n    ONN(\"XML parse did not fail\",\n        ne_xml_dispatch_request(req, parser) == NE_OK);\n\n    NE_DEBUG(NE_DBG_HTTP, \"error string: %s\\n\", ne_get_error(sess));\n\n    ONV(strstr(ne_get_error(sess), \"200 OK\") != NULL,\n        (\"no error string set on parse error: '%s'\", ne_get_error(sess)));\n\n    ne_xml_destroy(parser);\n    ne_request_destroy(req);\n    return destroy_and_wait(sess);\n}\n\nstatic int types(void)\n{\n    static const struct {\n        const char *type;\n        int is_xml;\n    } ts[] = {\n        { \"text/xml\", 1 },\n        { \"tExT/XmL\", 1 },\n        { \"text/html\", 0 },\n        { \"application/foo+xml\", 1 },\n        { \"aPpLiCaTION/FoOOO+xMl\", 1 },\n        { \"application/xml\", 1 },\n        { \"application/+xml\", 0 },\n        { \"application/fish+xml2\", 0 },\n        { \"foo/bar+xml\", 1 },\n        { \"f/b\", 0 },\n        { \"garble garble wotsit\", 0 }\n    };\n    unsigned n;\n\n    for (n = 0; n < sizeof(ts)/sizeof(ts[0]); n++) {\n        char resp[128];\n        ne_session *sess;\n        ne_request *req;\n        ne_xml_parser *parser;\n        int flag = 0;\n\n        ne_snprintf(resp, sizeof resp,\n                    \"HTTP/1.1 200 OK\\r\\n\"\n                    \"Content-Type: %s\\r\\n\"\n                    \"Connection: close\\r\\n\" \"\\r\\n\"\n                    \"<?xml version='1.0' encoding='UTF-8'?>\\n\"\n                    \"<hello/>\",\n                    ts[n].type);\n\n        CALL(make_session(&sess, single_serve_string, resp));\n    \n        req = ne_request_create(sess, \"PARSE\", \"/\");\n        parser = ne_xml_create();\n        \n        ne_xml_push_handler(parser, startelm, NULL, NULL, &flag);\n        \n        ONREQ(ne_xml_dispatch_request(req, parser));\n        \n        ONV(flag && !ts[n].is_xml,\n            (\"XML parser invoked for non-XML type: %s\", ts[n].type));\n        ONV(!flag && ts[n].is_xml,\n            (\"XML parser not invoked for XML type: %s\", ts[n].type));\n        \n        ne_xml_destroy(parser);\n        ne_request_destroy(req);\n        CALL(destroy_and_wait(sess));\n    }\n\n    return OK;\n}\n\nne_test tests[] = {\n    T(success),\n    T(failure),\n    T(fail_ctype),\n    T(types),\n    T(NULL)\n};\n\n"
  }
]